分支介绍
使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。在很多版本控制系统中,这是个昂贵的过程,常常需要创建一个源代码目录的完整副本,对大型项目来说会花费很长时间。但Git 的分支可谓是难以置信的轻量级,它的新建操作几乎可以在瞬间完成,并且在不同分支间切换起来也差不多一样快。和许多其他版本控制系统不同,Git 鼓励在工作流程中频繁使用分支与合并,哪怕一天之内进行许多次都没有关系。
Git 保存的不是文件差异或者变化量,而只是一系列文件快照。
可以把分支想象成一张便利贴,贴在某个commit上。当你在这个分支上提交了新代码,便利贴就自动往前挪一格,贴到最新的commit上。图谱里那些并行的彩线,不过在展示"这儿贴了一张便利贴,那儿也贴了一张",便利贴各自往前移动,轨迹自然就画出了不同的线。
因为这个机制,Git创建分支是近乎零成本的操作,就是写一个40字节的哈希值进去。图谱里每条线背后只是几个文件里记录的一个字符串而已。
Git可视化图谱由一堆圆点和连线构成。圆点就是commit节点,多半还会用不同颜色、实心空心来表示状态。线条则是提交之间的父子关系,实线通常表示直接的历史关联,虚线则大概率表示某个远程跟踪分支的位置。
VS Code自带的Graph 插件 为例,它会把当前分支的提交画成实心圆点,其他分支的提交画成空心圆点。
图谱上除了commit节点,还分布着各种"旗帜"和"标签"。分支名会显示在线条的末端,指向该分支最新的提交。标签(tag)则是一个固定不动的指针,通常指向某个里程碑版本,比如v1.0.0,它在图上常以特殊图标标出。
HEAD指向当前检出的分支或提交,在图上往往会高亮显示。它代表的是"当前工作区对应的位置"。很多操作,比如reset、checkout、rebase,本质上都是在移动HEAD和分支指针。
查看各分支,重点先要查看分支的HEAD的位置在哪个节点上。
因为图谱的视觉复杂度取决于两个因素:分支并行数和合并频率。
合并操作:图谱重新汇合。分支开发完了,总要把功能合回主干。在main分支上执行git merge feature-a,Git会找到两个分支的共同祖先,然后做一个三方合并。合并成功后会生成一个新的merge commit,这个commit有两个父提交,一个指向main原来的位置,一个指向feature-a的末端。
快进合并(fast-forward merge)在图谱上的表现是完全不同的。如果main分支从分出feature-a之后main分支没有产生新的提交,那么把feature-a合回main只需要把main指针直接往前挪到feature-a的位置,根本不需要生成merge commit。图谱上表现为两条线合为一条,没有任何交叉节点。很多新手不理解为什么有时候合并后图谱多条线、有时候不多条,其实区别就在这里。
怎么让图谱变干净:私有分支随便rebase,而共享分支老老实实用merge,或者用merge --no-ff制造清晰的合并节点。
VS Code内置的Source Control Graph插件适合日常开发,因为它和编辑器深度集成,顺手就能看,不需要额外开窗口。SourcTree是Atlassian家的免费工具,功能全面,对分支的展示方式也舒服,缺点是启动略慢。GitKraken则胜在界面漂亮,交互流畅,但商业使用要付费。
有时候执行合并时有一个fast-forward的方式可以选择,如果选择了fast-forward方式进行合并,实际上是把master分支头部的指针向上移动到new branch指针所在的位置,从图谱中看就是移动了标签,从而完成了合并。如果不选择fast-forward方式,那合并仍然会出现一个拐点会让new branch分支和master分支保持在各自的线上。不使用fast-forward方式进行合并一个好处就是可以从图谱上很明显的看到一个合并的动作,有利于分析分支状态,查看合并操作,防止有时候会忘记我的分支有没有合并过。 关于合并还有一种方式叫rebase(变基),这种属于更高级一些的操作用在特定场景,可以保持代码的整洁。
几种可视化文件比较和合并工具
diffmerge和P4merge最好用,kdiff比较专业些,支持自动merge。
P4Merge 是 Perforce 出品的可视化文件比较和合并工具,常被开发者用来查看代码差异、解决 Git 合并冲突,也支持图片对比。
免费好用的Diff和Merge工具大总结-腾讯云开发者社区-腾讯云
有两种使用分支的工作模式
长期分支
比如仅在 master 分支中保留完全稳定的代码,即已经发布或即将发布的代码。与此同时还有一个名为 develop 或 next 的平行分支,专门用于后续的开发,或仅用于稳定性测试 --- 一旦进入某种稳定状态,便可以把它合并到 master 里。这样,在确保这些已完成的特性分支(短期分支)能够通过所有测试,并且不会引入更多错误之后,就可以并到主干分支中,等待下一次的发布。
特性分支
特性(Topic)分支是指一个短期的,用来实现单一特性或与其相关工作的分支。在提交了若干更新后,可以把它们合并到主干分支,然后删除。该技术允许迅速且完全的进行语境切换 --- 因为工作分散在不同的流水线里,每个分支里的改变都和它的目标特性相关。可以把作出的改变保持在特性分支中几分钟,几天甚至几个月,等它们成熟以后再合并,而不用在乎它们建立的顺序或者进度。并且这些分支可以都是本地分支,这一点很重要。当在使用分支及合并的时候,一切都是在自己的 Git 仓库中进行的 --- 完全不涉及与服务器的交互。
什么是远程分支
远程分支(remote branch)是对远程仓库中的分支的索引。它们是一些无法移动的本地分支;只有在 Git 进行网络交互时才会更新。远程分支就像是书签,提醒着你上次连接远程仓库时上面各分支的位置。
用 (远程仓库名)/(分支名) 这样的形式表示远程分支。比如想看上次同 origin 仓库通讯时 master 分支的样子,就应该查看 origin/master 分支。如果你和同伴一起修复某个问题,但他们先推送了一个 iss53 分支到远程仓库,虽然你可能也有一个本地的 iss53 分支,但指向服务器上最新更新的却应该是 origin/iss53 分支。
假设有个地址为 git.ourcompany.com 的 Git 服务器。如果从这里克隆,Git 会自动为你将此远程仓库命名为 origin,并下载其中所有的数据,建立一个指向它的 master 分支的指针,在本地命名为 origin/master,但你无法在本地更改其数据。接着,Git 建立一个属于你自己的本地 master 分支,始于 origin 上 master 分支相同的位置,你可以就此开始工作。
强大的git checkout命令
git checkout 是 Git 中一个功能强大的命令,主要用于切换分支和恢复工作区文件。它可以帮助在不同分支之间快速切换,也可以将文件恢复到之前的某个提交状态。
不过需要注意的是,由于 git checkout 承担了两种不同的职责,Git 2.23 版本引入了更专用的 git switch(切换分支)和 git restore(恢复文件)命令。但 git checkout 依然广泛使用,理解它仍然很有必要。