本文主要是介绍基于rebase的Git工作流,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
参考:https://www.phpmianshi.com/?id=124
使用Git在多人协作的过程中,我们也会面临如何运用好Git的问题。这种情况下,就出现了各种各样的Git Workflow
,而本文将介绍一种基于rebase
的工作流,这种工作流也是目前开源社区所比较推崇的做法,了解了这种工作流之后可以更规范的使用Git
一、Rebase和Squash
1、Rebase是什么,为什么使用Rebase
rebase
是能够将我们对代码的更改从一个分支集成到另一个分支中的git命令之一(另一个命令是Merge
)。使用rebase
的一个风险在于,它会改写commit
历史,如果操作不当那么会是一种破坏性的操作。
风险总是与利益并存的,使用rebase
也好处良多,体现在于:
-
能够保持提交记录的清爽,不带来额外的提交历史(而使用
merge
会生成一条merge
的commit
) -
能够保持commit线的线性,保持成一条直线,从而能够容易地看出代码是如何推进的
2、Squash是什么,为什么使用Squash
rebase
可以运行在“交互(interactive)”
模式下,交互模式下的rebase
操作允许我们将多次commit
进行压缩,从而合并成更少的、甚至单一的一次提交。
之所以这么做,是因为在我们有很多commit
时,在最终合并到master
分支时,这些commit
就都会进入master
的commit
历史中,那么这会导致master
中的提交历史不那么可读。
举个例子,假设我们为某个feature
进行了多次commit
,每次commit
都只是做了一点点的更新,那么commit历史看起来就会杂乱无章。
比如我们的commit历史是这样的:
commit a commit b commit c
我们可以利用:
git rebase -i HEAD~3
把三个commit 合并成一个 commit
我们之所以频繁地提交commit
,是为了能够及时地存档,以便能够在需要的时候方便地回滚代码。但是为了修复特定问题、开发某个特性的多次小提交,其实是仅仅在当前开发上下文中有意义的,可能我们为此提交了十几个commit
,但是对于其他同事而言,他们可能就只想知道我们这次做了什么事情。那么通过Squash
这个操作,我们就能够将这些小commit
进行合并,组成一个有意义的commit
。
二、基本法则
在这套工作流中,有一些重要的法则,即:
-
在fork的仓库上拉分支 每个贡献者都应该
fork
代码仓库并且在该fork
出的仓库上进行开发。通过fork
仓库,就可以拥有独立的工作空间,从而可以放心大胆地进行开发、修改等,对于多人开发而言,还无需事先获得分支权限也能继续开发(Tips:其实并不建议多人在同一个分支上进行开发,因为这样子很容易导致合并冲突,如果某个feature
需要不止一个人去开发,相比只拉一个feature
分支,把大的feature
拆分为小的可独立工作单元其实是一种更好的实践) -
禁止对一个多人协作的分支进行rebase 这一点非常重要,贡献者只能对自己
fork
仓库的分支进行rebase
,这是因为rebase
会改写commit
历史,是比较危险的一种操作,只有对自己fork
仓库的分支进行rebase
,才不会有任何问题
三、工作角色
在这套工作流中,涉及两个角色:
-
Maintainer(维护者)
:维护者拥有仓库的写权限,他们可对Pull Request
进行Review
来决定通过或者拒绝,并且能创建Git Tag
用于发布 -
Contributor(贡献者)
:贡献者拥有仓库的读和fork
权限,可以查看和创建issue
,也可以提交Pull Request
。贡献者也负责解决合并冲突,此外贡献者仅能推送分支到自己fork
的仓库里
四、准备工作
在开始这套工作流之前,我们需要先做一些起始步骤。首先,需要先fork
项目仓库(通常原项目仓库惯称为upstream
,上游仓库);然后,在本地clone
这个fork
后的仓库(与此对应的远程仓库惯称为origin
);之后,在本地的remote
记录中添加这个upstream
仓库,具体步骤如下:
-
Fork
上游仓库,如在Gitlab
中可以点击右上角的“Fork”按钮,选择自己的空间,确定 -
在本地
clone
这个fork
后的仓库,如:
$ git clone git@git.phpmianshi.com:yang/app.git
-
添加上游仓库
$ git remote add upstream git@git.phpmianshi.com:php/app.git
-
确认信息:通过
git remote -v
确认我们是否成功进行了配置,正常而言需要显示两组记录(一组origin
,一组upstream
),如:
origin git@phpmianshi.com:yang/app.git (fetch) origin git@phpmianshi.com:yang/app.git (push) upstream git@phpmianshi.com:php/app.git (fetch) upstream git@phpmianshi.com:php/app.git (push)
五、工作流
好了,说了这么多前置知识,总算应该开始进入正题了。在工作流中,建议所提交的代码是关联一个user story(用户故事)
或者一个issue
的,可以和一些外部系统相关联(如JIRA
、VersionOne
),本套工作流的步骤总结如下:
-
第一步:
fetch
上游仓库的更新 -
第二步: 将
upstream/master
分支和本地master
合并 -
第三步: 在本地新建分支
-
第四步: 写代码、提交代码
-
第五步: 再次
fetch
上游仓库的更新(以同步在拉取分支之后upstream/master
中更新的内容) -
第六步: 对分支基于
upstream/master
进行rebase
和squash
,并且解决合并冲突(如果有) -
第七步: 推送分支
-
第八步: 发起一个
Pull Request
,进行Code Review
,Code Review
通过后,合并到master
,此后可以删除本地分支
以下是具体的细节:
1、fetch
上游仓库的更新
我们开发时,应当基于最新版本的代码库进行开发。国际惯例,我们一般将原始被fork的那个仓库成为upstream
仓库(上游仓库),通过fetch
命令,我们可以将upstream
中的内容获取下来存在本地,即执行:
$ git fetch upstream
2、将upstream/master
分支和本地master
合并
一般情况下,我们都是先拉取远程分支,然后基于此创建本地新分支,这样子就能够拥有最新的代码。不过在创建本地新分支前,我们可以先执行以下命令:
$ git checkout master $ git merge upstream/master
这样子将会执行一个快速合并(Fast-Forward)
来让master
和upstream/master
指向同一个提交
3、创建本地新分支
现在master
分支是最新的了,因此我们可以基于此来拉新分支:
$ git checkout -b feat-xyz
4、编写代码、提交代码
这一步就是开发的主要步骤了,开发过程中我们可以时不时地提交commit
(当然也要确保commit
是有意义的)
5、再次拉取代码
编码结束后,再发起一个Pull Request
合并上游仓库的master
分支之前,我们需要抓取一些upstream
里的新提交记录(这是因为对于原仓库而言,我们不是唯一的一个开发者)
为了保持和upstream/master
的同步,我们需要使用git fetch
:
$ git fetch upstream
6、Rebase和Squash
rebase
会改变原commit
所基于的分支(简称变基
),并且创建带着新SHA-1
哈希的新commit
(与此同时会保留原有提交信息)。而squash
会将多个commit
压缩为一个新的commit
(也可以是多个commit
)并且带上新的SHA-1
哈希值。通常情况下,我们会想要对目标合并分支进行rebase
,当最终创建Pull Request
的时候,这个rebase
和squash
后的分支就会从origin
仓库的分支进入到upstream
仓库的master分支里,所以我们需要rebase upstream/master
,为了执行squash
操作,我们需要运行交互模式的rebase
,如下:
$ git rebase --interactive upstream/master
这将会打开默认的编辑器,然后呈现将被rebase
的commit
列表,如:
pick 40d9fc0 feat: Add headline pick e8021a2 feat: Add Beijing pick 1525479 feat: Add Shanghai pick 81d2258 feat: Add Guangzhou pick e94d2fb feat: Add Shenzhen# Rebase ce9657d..e94d2fb onto ce9657d (5 commands)## Commands:# p, pick = use commit# r, reword = use commit, but edit the commit message# e, edit = use commit, but stop for amending# s, squash = use commit, but meld into previous commit# f, fixup = like "squash", but discard this commit's log message# x, exec = run command (the rest of the line) using shell# d, drop = remove commit## These lines can be re-ordered; they are executed from top to bottom.## If you remove a line here THAT COMMIT WILL BE LOST.## However, if you remove everything, the rebase will be aborted.## Note that empty commits are commented out
开头即为commit
列表,而#
中的内容则是对一些操作的解释。commit
列表中列出了从旧到新的每次commit
,然后我们可以使用说明里的命令选择对这些commit
执行怎样的一个操作,当我们操作完了后,可以保存文件然后退出编辑器。这之后,rebase
就会基于所选择的命令进行处理。
在rebase
过程中,可能会有合并冲突(比如你和upstream/master
里都修改了同个文件的同一部分),那么这时候,需要手动解决冲突,步骤如下:
-
通过
git status
查看哪些文件发生了冲突 -
手动解决冲突
-
运行
git add
来暂存文件 -
运行
git rebase --continue
来继续合并过程(不需要用git commit
来解决合并冲突)
git
会提示我们输入commit message
来作为这次压缩后的commit message
,所以我们通常需要让这条message
能够概括多次commit
的内容
7、推送分支
为了创建一个Pull Request
,我们需要将分支推送到origin
仓库,可以运行:
$ git push --set-upstream origin search
如果你已经推送过你的分支了,并且想要更新它,那么以上的命令会执行失败。这是因此rebase
改写了commit
历史,所以不再有一个公共的commit
,因此需要使用--force
选项(-f简写)来告诉git
放弃并覆盖远程分支,即:
$ git push origin HEAD:search -f Enumerating objects: 92, done. Counting objects: 100% (92/92), done. Delta compression using up to 8 threads Compressing objects: 100% (59/59), done. Writing objects: 100% (74/74), 12.02 KiB | 947.00 KiB/s, done. Total 74 (delta 58), reused 25 (delta 15), pack-reused 0 remote: remote: To create a merge request for search, visit: remote: https://git.phpmianshi.com.com/yang/app/merge_requests/new?merge_request%5Bsource_branch%5D=search remote: To git.phpmianshi.com:yang/app.git* [new branch] HEAD -> search
Tips: 以上也是为什么我们要在fork
分支上独立写代码的主要原因
8、发起一个Pull Request
到这里,是时候对上游仓库的master
分支发起一个来自origin
仓库search
分支的PR
了,可以直接复制上一步的输出结果中的url:
https://git.phpmianshi.com.com/yang/app/merge_requests/new?merge_request%5Bsource_branch%5D=search
就可以直接打开gitlab进行merge了,这时候点击“Compare && pull request”
便可进入发起PR
的流程
进入PR
创建页面后,我们可以填写对这个PR
的描述信息,然后点击Create pull request
便可成功发起PR
我们可以通过填写Reviewers
邀请同事进行Code Review
(与此同时,还可以通过CI
处理一些流程,比如校验代码格式、判断是否已经Review
通过,必须完成这项步骤才能合并代码)
在CI
(如果有)通过和Code Review
通过后,我们便可以点击Squash and merge
或者Rebase and merge
来合并代码到master
(这里我们推荐Squash and merge
,可以压缩多次commit
为一次):
此后,维护者接受PR,代码就会被自动合并到master
分支里,并且关闭该PR
。然后,我们也可以做一些后期清理工作:删除本地分支和远程分支(如search
和origin/search
),可以执行如下命令:
$ git branch -D search $ git push origin --delete search
到这里基本就结束了,欢迎留言沟通其他的git workflow 。谢谢
这篇关于基于rebase的Git工作流的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!