Git进阶教程:协同工作和分支操作全讲解 [Git Cheat Sheet]

没有财务自由,就没有思想自由。

——许小年

简单介绍一下Git协同工作中的分支操作,记录不同分支合并操作方法之异同。

在Git中合并分支有三种方法,分别是merge,rebase和cherry-pick,分别说说。

Git Merge 的三种方法

如上图所示,git merge 有如下特点:

  • 只处理一次冲突
  • 引入了一次合并的历史记录,合并后的所有 commit 会按照提交时间从旧到新排列
  • 所有的过程信息更多,可能会提高之后查找问题的难度

为什么讲 git merge 提交的信息过多可能会影响查找问题的难度呢?因为在一个大型项目中,单纯依靠 git merge 方法进行合并,会保存所有的提交过程的信息:引出分支,合并分支,在分支上再引出新的分支等等,类似这样的操作一多,提交历史信息就会显得杂乱,这时如果有问题需要查找就会比较困难了。

fast-forward

1
2
3
git checkout master	
# gco master
git merge test

如果带合并的分支在当前分支的下游,也就是说没有分叉时,会发生快速合并,从test分支切换到master分支,然后合并test分支。

这种方法相当于直接把master分支移动到test分支所在的地方,并移动HEAD指针。

fast-forward方式就是当条件允许的时候,git直接把HEAD指针指向合并分支的头,完成合并。属于“快进方式”,不过这种情况如果删除分支,则会丢失分支信息。因为在这个过程中没有创建commit。

no-ff

1
2
git checkout master
git merge –no-ff test

如果我们不想要快速合并,那么我们可以强制指定为非快速合并,只需加上–no-ff参数。

这种合并方法会在master分支上新建一个提交节点,从而完成合并。

squash

1
2
git checkout master
git merge --squash test

svn的在合并分支时采用的就是这种方式,squash会在当前分支新建一个提交节点。

squash和no-ff非常类似,区别只有一点不会保留对合入分支的引用。

git merge --squash 是用来把一些不必要commit进行压缩,比如说,你的feature在开发的时候写的commit很乱,那么我们合并的时候不希望把这些历史commit带过来,于是使用--squash进行合并,此时文件已经同合并后一样了,但不移动HEAD,不提交。需要进行一次额外的commit来“总结”一下,然后完成最终的合并。

总结

  • --no-ff:不使用fast-forward方式合并,保留分支的commit历史
  • --squash:使用squash方式合并,把多次分支commit历史压缩为一次

Git Rebase 交互模式和黄金准则

Rebase

git merge 一致,git rebase 的目的也是将一个分支的更改并入到另外一个分支中去。

如上图所示,他的主要特点如下:

  • 改变当前分支从 master 上拉出分支的位置
  • 没有多余的合并历史的记录,且合并后的 commit 顺序不一定按照 commit 的提交时间排列
  • 可能会多次解决同一个地方的冲突(有 squash 来解决)
  • 更清爽一些,master 分支上每个 commit 点都是相对独立完整的功能单元

那么我们现在来具体操作一下,看看 git rebase 是如何做的。

首先,和 git merge 不同的是,你需要在 feature 分支上进行 git rebase master 的操作,意味着让当前分支 feature 相对于 分支 master 进行变基:

在 feature 分支上执行 git rebase

可以看出,我们遇到了冲突,进行对比的双方分别是 master 分支的最新内容和 feature 分支的第一次提交的内容,上图下方红框内容告诉我们,在我们解决了冲突之后,需要执行 git rebase --continue 来继续变基的操作。

在解决冲突之后执行 git rebase --continue 时遇到了提示,看来我们首先需要把我们的修改存到暂存区,随后再执行 git rebase --continue。执行之后又遇到了冲突,这次是与 feature 分支的第二次提交进行对比出现的冲突,意味着我们需要多次解决同一个地方的冲突。

继续重复先解决冲突,再 git rebase --continue 的步骤,直到遇到:

意味着完成了 feature 最后一次提交的变基操作,至此整个变基就完成了。

再来看看执行 git rebase 之后的 feature 分支:

完全符合上面所说的执行 git rebase 的特点,我们引出 feature 分支的位置变了,没有多余的提交历史,且提交的时序也改变了,另外回忆一下,在我们执行变基的过程中也多次解决了同一个地方的冲突。

这个时候我们再切换到 master 分支上,将 feature 分支合并进来。

看得出来,feature 分支上的所有提交信息都会被合并到 master 分支上了,这些信息对我们来说不是必要的,我们在 masetr 分支上往往只需要知道合并进来了什么新的功能即可,这些多余的信息可以通过 git rebase 的交互模式进行整合

交互模式Rebase

打开变基的交互模式只需要传入一个参数 -i 即可,同时还需要指定对哪些提交进行处理,如:

1
git rebase -i HEAD~4

上述命令指定了对当前分支的最近四次提交进行操作。下面我们使用上面这行命令将 feature 分支的提交合并。

中间红框内有一些命令,可以用来处理某次提交的,此处我们使用 squash 来将所有的 commit 合并成一次提交,编辑并保存之后会出现编辑提交的信息的提示,编辑提交即可。

此时再看 feature 分支上的提交记录,会看到只有一次提交了。

此时无论是直接将分支合并到 master 还是先变基再合并,master 分支上的提交记录都会十分清爽了。

Rebase 的黄金法则

当你理解 rebase 是什么的时候,最重要的就是什么时候 不能 用 rebase。git rebase 的黄金法则便是,绝不要在公共的分支上使用它。

比如说,如果你把 master 分支 rebase 到你的 feature 分支上会发生什么:

这次 rebase 将 master 分支上的所有提交都移到了 feature 分支后面。问题是它只发生在你的代码仓库中,其他所有的开发者还在原来的 master 上工作。因为 rebase 引起了新的提交,Git 会认为你的 master 分支和其他人的 master 已经分叉了。

同步两个 master 分支的唯一办法是把它们 merge 到一起,导致一个额外的合并提交和两堆包含同样更改的提交。不用说,这会让人非常困惑。

所以,在你运行 git rebase 之前,一定要问问你自己「有没有别人正在这个分支上工作?」。如果答案是肯定的,那么把你的爪子放回去,重新找到一个无害的方式(如 git revert)来提交你的更改。不然的话,你可以随心所欲地重写历史。

总结

你使用 rebase 之前需要知道的知识点都在这了。如果你想要一个干净的、线性的提交历史,没有不必要的合并提交,你应该使用 git rebase 而不是 git merge 来并入其他分支上的更改。

另一方面,如果你想要保存项目完整的历史,并且避免重写公共分支上的 commit, 你可以使用 git merge。两种选项都很好用,但至少你现在多了 git rebase 这个选择。

cherry-pick

这命令简直就是神器,给你自由,你想把那个节点merge过来就把那个节点merge过来,其合入的不是分支而是提交节点

Git创建long commit message

使用git commit -m/gcmsg创建提交信息必须限制在50个字符内,那如何提交超长的commit message呢?

答案是使用git commit,git会弹出一个vim文本编辑控制台(也取决于git config中设置的默认编辑器),在vim中编辑分为headerbody两个部分。header部分遵循50字符的限制,body部分可以添加足够多和足够多行的信息。

丰富的commit message有利于减少collaborators之间信息沟通的能量消耗。

Git删除分支/删除远程分支/停止跟踪远程分支

1
2
3
4
5
6
7
8
9
10
11
# 查看远程分支
git branch -r

# 强制删除没有merge的本地分支
git branch -D branch-name

# 删除远程分支跟踪
git branch -r -d origin/branch-name

# 删除远程分支
git push origin :branch-name

Reference

  1. https://juejin.im/post/5af26c4d5188256728605809
  2. https://www.atlassian.com/git/tutorials/merging-vs-rebasing
  3. https://blog.csdn.net/qq_31024823/article/details/82787643
  4. https://zhuanlan.zhihu.com/p/28137908