git工作流以及--rebase的必要性

555 阅读3分钟

我们在做稍微大一点的项目一般都会分模块去开发,一个模块如果功能很复杂,这个模块还会安排多个开发人员共同参与开发,此时,我们最好是从 develop 分支单独切一个分支出来,命名为 feature/模块名称,参与这个模块开发的人都在这个分支上进行代码提交(不要直接以 develop 为源新建各自的分支,然后各自开发并提交至 develop 分支),这样可以最大程度地保证独立模块的开发不影响到 develop 分支。当然每天还是要跟 develop 同步一次,具体频率视情况而定。

git工作流

1. 以 develop 为源创建新分支(三种方式)

  • 先切到 develop 分支上,拉取最新代码,再新建一个分支并切换
    $ git checkout develop
    $ git pull --rebase
    $ git checkout -b feature/模块名称 // checkout -b 是新建分支branch与切换分支checkout的缩写
    
  • 直接以 develop 为源,新建并切换
    $ git checkout -b feature/模块名称 origin/develop
    

前面两种方式是先创建本地分支,远程仓库中并没有对应的同名远程分支,如何新建对应的同名远程分支,并建立两者的追踪关系,参考《新建本地分支后,如何推送到远程仓库上》

  • 直接在 gitlab 页面上点击 New branch image.png

    注意一定要选择以 develop 分支为源 image.png

第三种方式是先在gitlab页面上操作新建的远程分支,此时不能像前两种方式那样使用 git checkout -b feature/模块名称 origin/feature/模块名称,需要先fetch该远程分支,参考《git 拉取指定的远程分支到本地》

新建分支时注意命名规范,请参考《如何优雅地命名git分支》

2. 大家在新建的分支(feature/模块名称)上进行开发与代码提交

$ git add .
$ git commit -m "完成了什么功能or修复了什么bug"
$ git push

3. 每天上班到工位或者需要从 develop 分支上更新时

先确保本地代码已提交,两种方式

  • 先切换至 develop 本地分支
    $ git checkout develop
    $ git pull --rebase
    
    这样本地的 develop 分支已经更新,切回本地的模块分支,在本地的模块分支上去合并本地 develop 分支上的代码
    $ git checkout feature/模块名称
    $ git merge develop
    
  • 在当前模块分支上直接以 develop 为源进行 rebase 拉取
    $ git pull --rebase origin develop
    

--rebase的重要性

当我们在 push 本地分支的代码时,要先pull一次远程分支的代码,git pullgit pull --rebase 的区别你知道吗?

$ git pull // 相当于 git fetch + git merge
$ git pull --rebase // 相当于 git fetch + git rebase

两者的区别在于 git pull 之后 merge 与 rebase 的不同

提交树的不同

假设当前 develop 分支的提交记录如下

stateDiagram-v2
direction LR
commitId1 --> commitId2
commitId2 --> commitId3
commitId3 --> commitId4
commitId4 --> commitId5

如果我们在 commitId2 处切了一个新分支 temp 分支进行开发,有2次提交记录(commitId20,commitId21)

stateDiagram-v2
direction LR
commitId2 --> commitId20
commitId20 --> commitId21

commitId1 --> commitId2
commitId2 --> commitId3
commitId3 --> commitId4
commitId4 --> commitId5

在 temp 分支上开发完后,我们要合并至 develop 分支,先切到 develop 分支

  • 在 develop 分支上执行 git merge temp,就会得到如下的结果
    stateDiagram-v2
    direction LR
    commitId2 --> commitId20
    commitId20 --> commitId21
    commitId21 --> commitId6
    
    commitId1 --> commitId2
    commitId2 --> commitId3
    commitId3 --> commitId4
    commitId4 --> commitId5
    commitId5 --> commitId6
    
    merge新增了一次提交记录commitId6
  • 在 develop 分支上执行 git rebase temp,得到的是如下的结果
    stateDiagram-v2
    direction LR
    commitId1 --> commitId2
    commitId2 --> commitId20
    commitId20 --> commitId21
    commitId21 --> commitId3'
    commitId3' --> commitId4'
    commitId4' --> commitId5'
    
    rebase没有产生新的节点

使用rebase的git演进路线(提交树)是一直向前的,这样在版本回退时也很容易,用merge的git路线是跳跃的,如果版本回退你也找不到自己想要的版本

遇到冲突时的操作不同

  • merge 操作遇到冲突的时候,当前 merge 不能继续进行下去,手动修改冲突内容后,add 修改冲突后的内容,commit 就可以了
  • rebase 操作的话,会中断 rebase,同时会提示去解决冲突
    • 解决冲突后, 再执行 git rebase –continue 继续操作,再 push
    • 或者执行 git rebase –skip 忽略冲突

综上所述,想要更好的提交树,建议使用 rebase 操作会更好一点,这样可以线性地看到每一次提交,并且没有增加提交节点