关于Git分支工作流的一些笔记
写在前面
-
今天和小伙伴们分享一些Git分支工作流的笔记 -
学习的原因,希望通过学习了解 大型项目
的如何使用Git管理
-
博文为 《Pro Git》
读书笔记整理 -
感谢开源这本书的作者和把这本书翻译为中文的大佬们 -
理解不足小伙伴帮忙 指正
,书很不错,感兴趣小伙伴可以去拜读
下
「 傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。--------王小波」
分支开发工作流
大多数的时候,使用Git的开发者都喜欢只在master分支上保留完全稳定的代码
,一般为已经发布
或即将发布
的代码。
还有一些名为develop
或者next
的平行分支
,被用来做后续开发
或者测试稳定性
,这些分支不必保持绝对稳定
,但是一旦达到稳定状态
,它们就可以被合并入master分支
了。
类似下的样子,当然这里的分支周期很短
在这里插入图片描述这样,在确保这些已完成的主题分支(短期分支)
能够通过所有测试,并且不会引入更多bug之后,就可以合并入主干分支中,等待下一次的发布。
事实上我们刚才讨论的,是随着你的提交而不断右移的指针。稳定分支的指针总是在提交历史中落后一大截
,而前沿分支的指针往往比较靠前。
通常把他们想象成流水线(work silos)
可能更好理解一点,那些经过测试考验的提交会被遴选到更加稳定的流水线上去。
可以用这种方法维护不同层次的稳定性
。一些大型项目还有一个proposed(建议)
或pu:proposed updates(建议更新)分支
,它可能因包含一些不成熟的内容而不能进入next
或者master分支
。这么做的目的是使你的分支具有不同级别的稳定性
;
当它们具有一定程度的稳定性后,再把它们合并入具有更高级别稳定性的分支中。通过分支实现的工作流不是必须,但是对于复杂的项目往往很有帮助
主题分支
在master分支上工作到C1
,这时为了解决一个问题而新建iss91分支
,在iss91分支
上工作到C4
,然而对于那个问题你又有了新的想法,于是你再新建一个iss91v2
分支试图用另一种方法解决那个问题,接着你回到master
分支工作了一会儿,你又冒出了一个不太确定的想法,你便在C10
的时候新建一个dumbidea
分支,并在上面做些实验。你的提交历史看起来像下面这个样子:
现在,我们假设两件事情:你决定使用第二个方案来解决那个问题,即使用在iss91v2分支中方案
。
另外,你将dumbidea分支
拿给你的同事看过之后,结果发现这是个惊人之举。这时你可以抛弃iss91分支
(即丢弃C5和C6提交),然后把另外两个分支合并入主干分支
。最终你的提交历史看起来像下面这个样子:
$ git checkout master
$ git merge dumbidea
$ git merge dumbidea
当然这么多操作的时候,这些分支全部都存于本地。 当你新建和合并分支的时候,所有这一切都只发生在你本地的 Git 版本库中,没有与服务器发生交互。
远程分支
远程引用
是对远程仓库的引用(指针)
,你可以通过git 1s-remote<remote>
来显式地获得远程引用的完整列表,或者通过git remote show <remote>
获得远程分支的更多信息。然而,一个更常见的做法是利用远程跟踪分支
。
远程跟踪分支是远程分支状态的引用
。通俗的讲,希望在本地可以看到远程分支的状态,它们是你无法移动的本地引用。一旦你进行了网络通信,Git就会为你移动它们以精确反映远程仓库的状态
远程跟踪分支以<remote>/<branch>
的形式命名。例如,如果你想要看你最后一次与远程仓库origin
通信时master
分支的状态,你可以查看origin/master
分支。
「当你在Github或者Gitlab,Gitee上克隆一个项目,Git的clone
命令会为你自动将其命名为origin
,拉取它的所有数据,创建一个指向它的master分支的指针
,并且在本地将其命名为origin/master
。Git也会给你一个与origin的master分支在指向同一个地方的本地master分支
,这样你就有工作的基础。」
下图上面为远程厂库的分支情况,下面为克隆到本地的情况。
在这里插入图片描述master
是当你运行git init
时默认的起始分支名字,原因仅仅是它的广泛使用,origin
是当你运行git clone时默认的远程仓库名字。如果你运行git clone -o booyah
,那么你默认的远程分支名字将会是booyah/master
。
如果你在本地的master分支做了一些工作,在同一段时间内有其他人推送提交到 git.ourcompany.com
并且更新了它的master分支,这就是说你们的提交历史已走向不同的方向。即便这样,只要你保持不与origin 服务器连接(并拉取数据)
,你的origin/master
指针就不会移动。
**如果要与给定的远程仓库同步数据
**,运行git fetch <remote>命令
(在本例中为git fetch origin
)。这个命令查找“origin”是哪一个服务器(在本例中,它是git.ourcompany.com),从中抓取本地没有的数据,并且更新本地数据库,移动origin/master
指针到更新之后的位置。
添加远程仓库到当前Git版本库
为了演示有多个远程仓库与远程分支
的情况,我们假定你有另一个内部Git服务器,仅服务于你的某个敏捷开发团队。这个服务器位于git.teaml.ourcompany.com
。你可以运行git remote add
命令添加一个新的远程仓库引用到当前的项目
,将这个远程仓库命名为teamone
现在,可以运行git fetch teamone
来抓取远程仓库teamone有而本地没有的数据。因为那台服务器上现有的数据是origin服务器上的一个子集,所以Git并不会抓取数据而是会设置远程跟踪分支teamone/master
指向teamone的master分支
。
推送本地分支到远程
当你想要公开分享一个分支时,需要将其推送到有写入权限的远程仓库
上。如果你在本地新建的分支并做了commit,服务端会有一个申请合并的消息,在我日常的开发中,大都也是以这种方式来提交代码,
本地的分支并不会自动与远程仓库同步
—-你必须显式地推送想要分享的分支。这样,你就可以把不愿意分享的内容放到私人分支上,而将需要和别人协作的内容推送到公开分支。
如果希望和别人一起在名为serverfix
的分支上工作,你可以像推送第一个分支那样推送它。运行git push<remote><branch>
$ git push origin serverfix
Counting objects: 24, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (24/24), 1.91 KiB | 0 bytes/s, done.
Total 24 (delta 2), reused 0 (delta 0)
To https://github.com/schacon/simplegit
* [new branch] serverfix -> serverfix
也可以运行git push origin serverfix:serverfix
,推送本地的 serverfix分支,将其作为远程仓库的serverfix分支
如果并不想让远程仓库上的分支叫做 serverfix,可以运行git push origin serverfix:awesomebranch
来将本地的serverfix分支
推送到远程仓库上的awesomebranch分支
。
使用推送的远程分支
下一次其他协作者从服务器上抓取数据时 git fetch origin
,他们会在本地生成一个远程分支 origin/serverfix
,指向服务器的serverfix
分支的引用:
$ git fetch origin
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://github.com/schacon/simplegit
* [new branch] serverfix -> origin/serverfix
要特别注意的一点是当抓取到新的远程跟踪分支时,本地不会自动生成一份可编辑的副本(拷贝)。换一句话说,这种情况下,不会有一个新的serverfix分支——只有一个不可以修改的origin/serverfix指针。
可以运行git merge origin/serverfix
将这些工作合并到当前所在的分支
。
如果想要在自己的serverfix分支上工作
可以新建分支在远程跟踪分支之上
:
$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
这会给你一个用于工作的本地分支serverfix
,并且起点位于 origin/serverfix
。
跟踪分支
从一个远程跟踪分支检出一个本地分支
会自动创建所谓的“跟踪分支”
(它跟踪的分支叫做“上游分支”)。跟踪分支是与远程分支有直接关系的本地分支
。如果在一个跟踪分支上输入git pu11
,Git能自动地识别去哪91个服务器上抓取、合并到哪个分支。
当克隆一个仓库时,它通常会自动地创建一个跟踪origin/master
的master分支
。然而,如果你愿意的话可以设置其他的跟踪分支,或是一个在其他远程仓库上的跟踪分支,又或者不跟踪master分支。最简单的实例就是像之前看到的那样,运行git checkout-b <branch><remote>/<branch>
。
$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
这是一个十分常用的操作所以Git 提供了--track
快捷方式,该捷径本身还有一个捷径,如果你尝试检处的分支不存在且刚好有一个远程分支与之对应,那么Git就会为你创建一个远跟踪分支。
$ git checkout serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
设置已有的本地分支跟踪一个刚刚拉取下来的远程分支,或者想要修改正在跟踪的上游分支,你可以在任意时间使用-u或--set-upstream-to
选项运行git branch
来显式地设置。
$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
拉取 fetch和pull的区别
当git fetch
命令从服务器上抓取本地没有的数据时,它并不会修改工作目录中的内容。它只会获取数据然后让你自己合并
。
git pull
在大多数情况下它的含义是一个git fetch紧接着一个git merge命令
。
由于git pull
的魔法经常令人困惑所以通常单独显式地使用fetch与merge命令会更好一些。
删除远程分支
可以运行带有--delete
选项的git push
命令来删除一个远程分支。 如果想要从服务器上删除 serverfix 分支
,运行下面的命令:
$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
- [deleted] serverfix
基本上这个命令做的只是从服务器上移除这个指针。 Git 服务器通常会保留数据一段时间直到垃圾回收运行
,所以如果不小心删除掉了,通常是很容易恢复的。
这一章中,你将会学习如何作为贡献者或整合者,在一个分布式协作的环境中使用Git。你会学习为一个项目成功地贡献代码
,并接触一些最佳实践方式,让你和项目的维护者能轻松地完成这个过程。另外,你也会学到如何管理有很多开发者提交贡献的项目。
分布式工作流程
与传统的集中式版本控制系统(CVCS)相反,Git的分布式特性
使得开发者间的协作变得更加灵活多样。
在集中式系统中,每个开发者就像是连接在集线器上的节点,彼此的工作方式大体相像。而在分布式Git中,每个开发者同时扮演着节点和集线器的角色,也就是说,每个开发者既可以将自己的代码贡献到其他的仓库中,同时也能维护自己的公开仓库,让其他人可以在其基础上工作并贡献代码。
Git的分布式协作可以为项目和团队衍生出种种不同的工作流程,一起来学习下
集中式工作流
集中式系统中通常使用的是单点协作模型——集中式工作流
。一个中心集线器,或者说仓库,可以接受代码,所有人将自己的工作与之同步。若干个开发者则作为节点,即作为中心仓库的消费者与中心仓库同步。
例如John和Jessica同时开始工作。John完成了他的修改并推送到服务器。接着Jessica尝试提交她自己的修改,却遭到服务器拒绝。她被告知她的修改正通过非快进式(non-fast-forward)的方式推送
,只有将数据抓取下来并且合并
后方能推送。这种模式的工作流程的使用非常广泛,因为大多数人对其很熟悉也很习惯。
当然这并不局限于小团队。利用Git的分支模型,通过同时在多个分支上工作的方式,即使是上百人的开发团队也可以很好地在单个项目上协作。
集成管理者工作流
Git允许多个远程仓库存在,使得这样一种工作流成为可能:
每个开发者拥有自己仓库的写权限和其他所有人仓库的读权限
。这种情形下通常会有个代表“官方”项目的权威的仓库
。
要为这个项目做贡献,你需要从该项目克隆出一个自己的公开仓库
,然后将自己的修改推送上去。接着你可以请求官方仓库的维护者拉取更新合并
到主项目。
维护者可以将你的仓库作为远程仓库添加进来,在本地测试你的变更,将其合并入他们的分支并推送回官方仓库。这一流程的工作方式如下所示
在这里插入图片描述基本流程
-
项目维护者推送到主仓库。 -
贡献者克隆此仓库,做出修改。 -
贡献者将数据推送到自己的公开仓库。 -
贡献者给维护者发送邮件,请求拉取自己的更新。 -
维护者在自己本地的仓库中, 将贡献者的仓库加为远程仓库并合并修改
。 -
维护者将合并后的修改推送到主仓库。
这也是GitHub和GitLab等集线器式(hub-based)工具最常用的工作流程。
人们可以容易地将某个项目派生成为自己的公开仓库,向这个仓库推送自己的修改,并为每个人所见。这么做最主要的优点之一是你可以持续地工作,而主仓库的维护者可以随时拉取你的修改。贡献者不必等待维护者处理完提交的更新——每一方都可以按照自己的节奏工作。
主管与副主管工作流
这其实是多仓库工作流程的变种。一般拥有数百位协作开发者的超大型项目
才会用到这样的工作方式,例如著名的Linux内核项目
。被称为副主管(lieutenant)
的各个集成管理者
分别负责集成项目中的特定部分。所有这些副主管头上还有一位称为主管(dictator)
的总集成管理者负责统筹。主管维护的仓库作为参考仓库,为所有协作者提供他们需要拉取的项目代码。整个流程看起来是这样的(见主管与副主管工作流。):
-
普通开发者在自己的 主题分支
上工作,并根据master分支
进行变基
。这里是主管推送的参考仓库的master分支。 -
副主管将普通开发者的主题分支合并到自己的 master分支
中。 -
主管将所有副主管的 master分支
并入自己的master分支
中。 -
最后,主管将集成后的 master分支
推送到参考仓库中,以便所有其他开发者以此为基础进行变基
。
这种工作流程并不常用,只有当项目极为庞杂,或者需要多级别管理时,才会体现出优势。利用这种方式,项目总负责人(即主管)可以把大量分散的集成工作委托给不同的小组负责人分别处理,然后在不同时刻将大块的代码子集统筹起来,用于之后的整合。
博文参考
《Pro Git》
- 点赞
- 收藏
- 关注作者
评论(0)