Git 使用小结

340 阅读7分钟

在我们使用 git 的过程中,分支合并是常见的操作,用 merge 或 rebase 都能达到目的,但是使用 rebase 能合并 commit,使合并的 commit 代表一个小功能,这样 code reviewer 能根据合并的 commit 看代码,减轻 reviewer 的压力,同时 rebase 还能实现变基,使得 graph 可读性变强。本文分为两个部分,第一部分是对一个特定的开发流程,分别使用 merge 和 rebase,对比 graph 和 commit,说明 rebase 合并 commit 和变基这 2 个功能的优点;第二部分是对 git 基本工作原理与常用命令的小结。

一、merge vs rebase

在我们的工作中,选择一个合适的开发流程,有利于多人协作开发,推荐下图的开发流程,mrege 与 rebase 的使用,也是基于下图的开发流程。

图一:

图一的开发流程,简述如下:

(1)拉去最新的主干分支到本地,基于主干分支创建自己的分支;

(2)在自己的分支开发完后,推到 git 服务器上,并提一个 PR;

(3)reviewer 接受 PR,将自己的分支合并进主干分支,结束本轮开发。

1.1、使用 merge

我们模拟两个同学按照上述流程进行开发,首先在 github 上创建一个 gitskills 仓库,创建仓库的时候,选择自动创建 README.md 文件,如下图所示:

图二:

在本地新建 A 和 B 文件夹,分别用来模拟 2 个同学的开发流程,如下图所示:

图三:

分别在 A 和 B 文件夹下执行 git clone git@github.com:Lcf2211974/gitskills.git 命令。

好了,准备工作做好,可以愉快地模拟两个同学的开发过程了。

以下操作过程基于 A/gitskills 文件夹:

创建自己的分支 git checkout -b dev1;

对 README.md 进行 2 次修改,2 次提交;

将 dev1 push 到 github 上,提一个 PR;

接受 PR,在 github 上,将 dev1 合进主干。

操作如下图所示:

图四:

这时候 git checkout main,在 git pull 一下,执行 git loggit log --graph --pretty=oneline --abbrev-commit,分别看下主干的提交情况,和 graph,如下图所示:

图五:

可以看到主干有 4 个 commit,graph 可读性较强,这里有什么问题吗,有,如果 add 1 和 add 2 这两个 commit 是一个小功能点,完全可以将 add 1 和 add 2 合并成一个 commit,使主干的 commit 更加整洁,这个可以用 rebase 实现,后面再说。

好了,在 A/gitskills 上开发完了,现在可以在 B/gitskills 上进行开发。

以下操作过程基于 B/gitskills 文件夹:

创建自己的分支 git checkout -b dev2;

对 README.md 进行 2 次修改,2 次提交;

拉取最新的主干,合并到 dev2 分支上;

将 dev2 push 到 github 上,提一个 PR;

接受 PR,在 github 上,将 dev2 合进主干。

操作如下图所示:

图六:

这时候 git checkout main,在 git pull 一下,执行 git log --onelinegit log --graph --pretty=oneline --abbrev-commit,分别看下主干的提交情况,和 graph,如下图所示:

图七:

可以看出,这时候,主干已经有 8 次 commit,graph 的可读性已经降低了很多,这次模拟了 2 个同学的一轮开发,如果多人持续像这样开发下去,graph 基本没有去看的必要,主干的 commit 会变得琐碎而繁多,想根据 commit 去看代码功能变动,已经很困难了,下面我们用 rebase 优化 graph,与主干的 commit。

在开始用 rebase 优化 graph 和主干 commit 之前,我们先来看看 merge 这个操作,比较有意思的点:

在将 main 合并进 dev2 之前,2 个分支是长这样的:

图八:

在将 main 合并进 dev2 之后,2 个分支是长这样的:

图九:

在 dev2 分支执行下 git log 印证:

图十:

在 dev2 上,将 commit 回退到 E,dev2 分支就变成了下面这样:

图十一:

实际印证下:

图十二:

同样,在 dev2 上,将 commit 回退到 B,dev2 分支就变成了下面这样:

图十三:

merge 这样设计是非常合理的,如果不明白,可以自己设想下,合并后,分支应该长啥样,就会明白 merge 的做法有多么合理了。

merge 就到这了,下面开始 rebase。

1.2 使用 rebase

还是和 merge 的流程一样:

以下操作在 A/gitskills 文件夹下完成:

在修改 2 次 README.md 文件后,执行 git rebase -i main,这条命令既能变基又能合并 commit,但是在这里看不出变基的效果,就先看下合并 commit 的效果吧,其中参数 i 是打开交互界面。

执行 git rebase -i main 之后,交互界面如下:

图十四:

将命令用中文解释以下,中文解释抄的阮一峰老师对命令的解释:

  • pick:正常选中
  • reword:选中,并且修改提交信息;
  • edit:选中,rebase时会暂停,允许你修改这个commit(参考这里)
  • squash:选中,会将当前commit与上一个commit合并
  • fixup:与squash相同,但不会保存当前commit的提交信息
  • exec:执行其他shell命令

我对 add 1 这个 commit 运用 reword 命令,对 add 2 这个 commit 运用 fixup 这个命令,保存,退出,如下图所示:

图十五:

对 commit 运用命令,保存,推出后,就进入到修改注释的页面,如下图所示:

图十六:

修改完注释后,保存退出,然后我们用 git log 看下 dev1 的 commit 情况,如下图所示:

图十七:

我们看到,2 个 commit 被合并成了一个 commit,执行完 rebase 操作后,我们还是将 dev1 推到 github,并提一个 PR,接受 PR,将 dev1 合进主干,切换到 main 分支,看下 commit 情况和 graph 图情况,如下图所示:

图十八:

和 merge 那边对比,似乎作用不大,就是减少了 1 个 commit,别急,在这里还没有体现 rebase 变基的功能。

完成了在 A/gitskills 上的开发,我们接着在 B/gitskills 上开发:

以下操作基于 B/gitskills 文件夹:

对 README.md 进行两次修改,提交 2 次,然后从 github 上拉取最新的主干分支,在 dev2 分支上执行 git rebase -i main,依然是对每个 commit 运用命令,我这里还是选择对 add 3 运用 reword 命令,对 add 4 运用 fixup 命令,运用完命令后,因为有冲突,所以没有弹出修改注释的界面,如下图所示:

图十九:

在 README.md 解决完第一次冲突后,执行 git add .,然后执行 git rebase --continue,会弹出修改注释的界面,我们把注释修改为 add 3 4,然后在 README.md 中解决第二次冲突,解决完后,接着执行 git add .git rebase --continue,因为 add 4 这个 commit,我们是把它合进 add 3 这个 commit,并且不要注释,所以不需要修改注释,直接退出修改注释界面即可。至此,就完成了 rebase 操作,然后,我们看下 dev2 分支上 commit 和 graph 情况:

图二十:

可以看出,使用 rebase 后,dev2 的 commit 和 graph 较使用 merge 整洁了许多。

通过上面一顿操作,大家应该明白了 rebase 的变基原理了吧,下面用图说话:

使用 rebase 之前,main 和 dev2 分支长下面这样:

图二十一:

使用 rebase 之后,main 和 dev2 分支长下面这样:

图二十二:

在 rebase 时,会先比较 dev2 和 main 的分叉点,A 就是分叉点,然后将 D、E 保存下来,把 B、C 运用到 dev2 上,然后 D 就是基于 C 做的修改了,我们顺便把 E 合进了 D,因为 D 是基于 C 之后的修改,所以 main 合进 dev2 时,不会产生一个合并 commit。

理解了 rebase 的合并和变基原理,我们接着走完剩下的流程,将 rebase 后的 dev2 分支推到 github 上,提一个 PR,接受 PR,将 dev2 合进主干,将最新的主干拉下来,看下 commit 和 graph,如下图所示:

图二十三:

可以看出 commit 是基于功能点的,graph 可读性很强,如果团队中的每一个人,按照上述流程开发,graph 会如上图一直延续下去,commit 是基于功能点,我们可以通过阅读 commit,看清代码是如何迭代的。

今天就到这了,明天还要上班,git 基本原理和常用命令小结,以及总结等,就放在后面更新了。