Pro Git 笔记(2)

Pro Git 笔记(2)

第 3 章 Git 分支机制

分支机制简述

提交对象

当我们发起提交时,Git 储存的是提交对象,其中包含了指向暂存区快照的指针。提交对象也包括作者姓名和邮箱地址、已输入的提交信息和**指向父提交的 指针 **。 初始提交没有父提交,一般的提交会有一个父提交,两个以上分支的合并提交有多个父提交。

提交对象包括元数据以及指向项目根目录的树对象的指针,以便在需要的时候重新创建这次快照。(不大明白元数据的意思,Google 了一下也没有看到解释,感觉是文件的二进制数据?如果您理解这里,请在评论中赐教。) 树对象,记录着目录结构以及 blob 对象和文件名之间的对应关系。(个人感觉算是拍下的文件快照) blob 对象,保存了提交的文件的内容。

分支理解

Git 的分支只不过是一个指向某次提交的轻量级的可移动指针,每次提交时都会自动向前移动。

个人理解(不一定对):就像听说的 Java 中垃圾回收机制里内存的理解一样。Java 中的内存就像是这里每次提交的对象,提交对象中指向父提交的指针就像是内存之间的指针;分支就像是 Java 中没有,但 C/C++ 中常用的指针一样,指向我们最新创建的内存(提交的对象),以便于我们对这块内存(提交对象)进行操作;我们删除某一个分支的操作就像 Java 中的垃圾回收一样,垃圾回收是自动回收开辟后找不到了的内存。首先这需要找到指向最近开辟内存(提交对象)的指针(分支),我们删除指针(分支)后就找不到开辟的内存的地址(提交对象的校验码)。然后 Java 会顺着最新开辟的内存一步步删除它指针指向的前面的内存,知道最后删除的内存没有指向其他内存的指针;而(个人猜想)Git 中应该也是类似顺着刚才分支指向的提交对象一步步删除之前同一分支上的提交(感觉毕竟不能一个分支删除以后还存留着数据吧,那样岂不是文件会有很多没用的数据),直到遇到是其他分支祖先的提交对象停止,不过感觉应该也是和 Java 的 GC 机制一样不会立刻删除。 话说这样理解起来 Java 的 GC 原理和 Git 的分支好像啊,当初还是在 Sedgewick 老爷子的算法书里图论的应用看到 GC 机制的,果然数学是所有自然学科之母啊…

感慨:

难怪 Linus 说是思考数据结构写出的 Git,很多技术大牛也说 程序 = 数据结构 + 算法,这样想来,Git 的设计简直太巧妙和优雅了!

抖个机灵:

技术大牛:程序 = 数据结构 + 算法 我等菜鸡:程序 = 搜索引擎 + 英语

技术大牛:面向过程/对象编程 我等菜鸡:面向 Google/Baidu 编程

分支常用命令:

只创建新分支:git branch [branch-name] 切换分支:git checkout [branch-name] 查看分支指向对象:git log –decorate 查看分支历史:git log –oneline –decorate –graph –all

其他注意点:

Git 维护着一个名为 HEAD 的特殊指针,这是一个指向当前所在的本地分支的指针。

切换分支命令改变的就是 HEAD 指针,使其指向其他分支。

分支切换会更改工作目录文件,所以如果 Git 在当前状态下无法干净地完成恢复操作时,就不允许切换分支。

Git 中的分支实际上就是一个简单的文件,其中只包含了该分支所指向提交的长度为 40 个字符的 SHA-1 校验和。正因如此,Git 分支切换和删除的成本很低。

基本的分支和合并操作

基本的分支操作

创建并切换到新分支:git checkout -b [branch-name]

合并分支:git merge [branch-name]

合并分支的两种方式
  • 当你尝试合并两个不同的提交,而顺着其中一个提交可以直接到达另一个提交时,Git 会简化合并操作,直接把分支指针向前移动,因为这种单线历史不存在有分歧的工作。这就叫做 fast-forward
  • 开发历史从早先的某个时间点开始有了分叉时,Git 要做一些额外的操作。Git 执行的操作是简单的三方合并。三方合并会使用两个待合并分支上最新提交的快照,以及这两个分支的共同祖先(Git 会自己判断最优的共同祖先作为合并基础)的提交快照。与上一种方式不同,这次 Git 会基于三方合并的结果创建新的快照,然后再创建一个提交指向新建的快照。这个提交叫作“合并提交”,它拥有不止一个父提交。
合并冲突的处理

理想很丰满,现实很骨感。什么问题都不出的合并还是比较少的…

如果合并的两个分支上都改了同一个文件的同一部分内容,Git 就没办法干净地合并这两个分支。Git 会暂停整个合并过程,等待你解决冲突。发生冲突后可以执行 git status 查看哪些文件没有被合并以便于解决冲突。

可以选择使用任一版本的内容或是自己整合的内容来解决冲突。在解决了每个冲突文件的冲突部分后,可以执行 git add 把文件标记为冲突已解决状态。

最终通过 git commit 完成这次合并提交。如果想给将来审阅这次合并的人一点帮助,可以修改一下合并信息,提供更多这次合并的细节,比如做了什么和为什么这样做。

分支管理

常用命令和参数

查看当前所有分支的短列表:git branch 查看每个分支上的提交和提交信息:git branch -v 查看已并入当前分支的所有分支(应该是用来查看可以删除的分支):git branch –merged 查看包含尚未合并的工作的所有分支:git branch –no-merged 删除已合并的分支:git branch -d [branch-name] 删除尚未合并到主线的分支(这样会丢弃该分支上所有工作):git branch-D [branch-name]

与分支有关的工作流

长期分支(适用于大型项目和复杂项目)

其中一种流程就是在 master 分支只存放稳定版的代码(已经发布或即将发布版本)。使用另一个叫作 develop 或 next 的平行分支用于开发,或测试代码的稳定性,一旦达到稳定版本的状态就合并到 master 分支上。

主题分支(任何规模的项目都适用)

主题分支是指短期的、用于实现某一特定功能及其相关工作的分支。

远程分支

远程分支的表现形式是 —— (remote)/(branch)

跟踪分支(上游分支)是基于远程分支创建的本地分支,与远程分支直接关联。(git push 和 git pull 时有对应的远程分支)

基本命令与参数

把本地分支推送到远程分支以更新远程数据:git push (remote) (branch)

本地分支推送到远程不同名称的分支:git push (remote) (branch):(local-branch)

合并新的远程跟踪分支:git merge (remote)/(branch)

根据新的远程跟踪分支创建本地新分支:git checkout -b (local-branch) (remote)/(branch)

创建跟踪分支(想切换的分支尚未创建且名称和远程分支一致):git checkout (branch-name)

给本地分支设置跟踪分支(或更改对应远程分支):git branch -u(或 –set-upstream-to) [remote]/[branch-name]

查看设置了哪些跟踪分支:git branch -vv 这个还会显示本地分支和远程分支的提交差距(领先/落后),不过是和上次从各个服务器读取的数据算的,也就是当前本地的 origin/master 分支。

删除远程分支:git push (remote) –delete (branch-name)

变基 (rebase)

基本操作和原理

变基和合并都是把更改从一个分支整合到另一个分支的主要方式。

rebase 命令,会把某个分支上所有提交的更改在另一个分支上重现一遍。

变基的工作原理:首先找到两个要整合的分支(你当前所在的分支和要整合的分支(基底分支))的共同祖先,然后取得当前所在分支的每次提交引入的更改(diff),并把这些更改存为临时文件,然后将当前分支重置为要整合到的分支,最后在该分支上以此引入之前保存的每一次更改。 变基操作后就可以回到 master 分支进行 fast-forward 合并。

变基操作配合 Learn Git Branching 的可视化图像理解更佳。

变基操作和合并操作最终得到的合并提交快照内容一样,不同的是得到的提交历史。变基操作得到的提交历史更简洁,看起来像一条线。

有趣的变基操作(执行起来很酷但说起来比较复杂)

没有图说起来比较麻烦……

从一个祖先的分叉提交几次后又出现一个分叉,现在你只想要第二次分叉中某个分支的独有工作,但不想要第一次分叉到第二次分叉之间的部分工作。

可以使用 git rebase –onto master(基底) branch1 branch2,大意就是:将当前分支切换到 branch2,找出 master 和 branch1 的共同祖先提交,然后把自从共同祖先以来 branch2 分支上独有的工作在 master 分支上重现。

变基操作的潜在危害

变基的缺点总结成一句话:不要对已经存在于本地仓库之外的提交执行变基操作。

总结变基和合并操作的优点:对本地尚未推送的更改进行变基操作,简化提交历史,但绝不能对任何已经推送到服务器的更改进行变基操作。

说起来比较麻烦,所以对于变基的态度就是 —— 只在需要的时候执行变基操作。

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦