内容简介:Git是目前最为强大的代码版本管理工具,被开源社区和各大公司所广泛使用。使用Git进行团队协作开发是很便利的一件事情,但是在多人协作的过程中,我们也会面临如何运用好Git的问题。这种情况下,就出现了各种各样的风险总是与利益并存的,使用
Git是目前最为强大的代码版本管理工具,被开源社区和各大公司所广泛使用。使用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历史看起来会像是这样:
e94d2fb (HEAD -> feat-china) feat: Add Shenzhen 81d2258 feat: Add Guangzhou 1525479 feat: Add Shanghai e8021a2 feat: Add Beijing 40d9fc0 feat: Add headline ce9657d (upstream/master, origin/master, origin/HEAD, master) feat: i18n (#1) ab15f4f feat(i18n): Add support for Japanese a39b290 feat: Add new headline 4774815 Initial commit
我们之所以频繁地提交 commit
,是为了能够及时地存档,以便能够在需要的时候方便地回滚代码。但是为了修复特定问题、开发某个特性的多次小提交,其实是仅仅在当前开发上下文中有意义的,可能我们为此提交了十几个 commit
,但是对于其他同事而言,他们可能就只想知道我们这次做了什么事情。那么通过 Squash
这个操作,我们就能够将这些小 commit
进行合并,组成一个有意义的 commit
。以下是用了 Squash
后的结果:
c27766b (Head -> feat-china) feat: show first-tier cities of China 4774815 (master) Initial 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
上游仓库,如在Github
中可以点击右上角的“Fork”按钮:
- 在本地
clone
这个fork
后的仓库,如:
$ git clone [email protected]:RuphiLau/playgit.git $ cd playgit
- 添加上游仓库
$ git remote add upstream [email protected]:trialground/playgit.git
- 确认信息:通过
git remote -v
确认我们是否成功进行了配置,正常而言需要显示两组记录(一组origin
,一组upstream
),如:
origin [email protected]:RuphiLau/playgit.git (fetch) origin [email protected]:RuphiLau/playgit.git (push) upstream [email protected]:trialground/playgit.git (fetch) upstream [email protected]:trialground/playgit.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
示例流程图:
ORIGIN: master: A->B UPSTREAM: master: A->B->C LOCAL: master: A->B origin/master: A->B upstream/master: A->B->C # 获取结果
2、将 upstream/master
分支和本地 master
合并
一般情况下,我们都是先拉取远程分支,然后基于此创建本地新分支,这样子就能够拥有最新的代码。不过在创建本地新分支前,我们可以先执行以下命令:
$ git checkout master $ git merge upstream/master
这样子将会执行一个 快速合并(Fast-Forward)
来让 master
和 upstream/master
指向同一个提交,示例图:
ORIGIN: master: A->B UPSTREAM: master: A->B->C LOCAL: master: A->B->C # 新增了C origin/master: A->B upstream/master: A->B->C
3、创建本地新分支
现在 master
分支是最新的了,因此我们可以基于此来拉新分支:
$ git checkout -b feat-xyz
示例图:
ORIGIN: master: A->B UPSTREAM: master: A->B->C LOCAL: master: A->B->C origin/master: A->B upstream/master: A->B->C feat-xyz: A->B->C # 新增了 feat-xyz 分支
4、编写代码、提交代码
这一步就是开发的主要步骤了,开发过程中我们可以时不时地提交 commit
(当然也要确保 commit
是有意义的),示例图:
ORIGIN: master: A->B UPSTREAM: master: A->B->C LOCAL: master: A->B->C origin/master: A->B upstream/master: A->B->C feat-xyz: A->B->C->D->E->F # 新增了 D、E、F 三次 commit
5、再次拉取代码
编码结束后,在发起一个 Pull Request
合并上游仓库的 master
分支之前,我们需要抓取一些 upstream
里的新提交记录(这是因为对于原仓库而言,我们不是唯一的一个开发者),示例图:
ORIGIN: master: A->B UPSTREAM: master: A->B->C->C2->C3 # 其他人新提交了 C2、C3 两次 commit LOCAL: master: A->B->C origin/master: A->B upstream/master: A->B->C feat-xyz: A->B->C->D->E->F
为了保持和 upstream/master
的同步,我们需要使用 git fetch
:
$ git fetch upstream
拉取之后,示例图:
LOCAL: master: A->B->C origin/master: A->B upstream/master: A->B->C->C2->C3 # 拉取结果 feat-xyz: A->B->C->D->E->F
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
来解决合并冲突)
rebase
之后的示例图如下:
ORIGIN: master: A->B UPSTREAM: master: A->B->C->C2->C3 LOCAL: master: A->B->C origin/master: A->B upstream/master: A->B->C->C2->C3 feat-xyz: A->B->C->C2->C3->D->E->F # Rebase结果
如果我们还执行了 squash
操作,那么这多次的 commit
会被压缩, git
会提示我们输入 commit message
来作为这次压缩后的 commit message
,所以我们通常需要让这条 message
能够概括多次 commit
的内容,示例图:
LOCAL: master: A->B->C origin/master: A->B upstream/master: A->B->C->C2->C3 feat-xyz: A->B->C->C2->C3->DEF # Squash结果
7、推送分支
为了创建一个 Pull Request
,我们需要将分支推送到 origin
仓库,可以运行:
$ git push --set-upstream origin feat-china
如果你已经推送过你的分支了,并且想要更新它,那么以上的命令会执行失败。这是因此 rebase
改写了 commit
历史,所以不再有一个公共的 commit
,因此需要使用 --force
选项来告诉 git
放弃并覆盖远程分支,即:
$ git push --force origin feat-china
Tips:以上也是为什么我们要在 fork
分支上独立写代码的主要原因
8、发起一个Pull Request
到这里,是时候对上游仓库的 master
分支发起一个来自 origin
仓库 feat-china
分支的 PR
了,通常在我们 push
之后,在 github
中可以看到如下图所示:
这时候点击 “Compare && pull request”
便可进入发起 PR
的流程
ORIGIN: master: A->B feat-xyz: A->B->C->C2->C3->DEF ---- | Pull Request UPSTREAM: | master: A->B->C->C2->C3 <----
进入 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
。然后,我们也可以做一些后期清理工作:删除本地分支和远程分支(如 feat-china
和 origin/feat-china
),可以执行如下命令:
$ git branch -D feat-china $ git push origin --delete feat-china
最终效果为:
ORIGIN: master: A->B UPSTREAM: master: A->B->C->C2->C3->DEF LOCAL: master: A->B->C origin/master: A->B upstream/master: A->B->C->C2->C3->DEF
六、成果
现在,让我们来看一下这个工作流带来的成果,以下是以上步骤完成后,所呈现出的一个 commit
历史:
怎么样,是不是又干净又清爽呢?I do believe that you'll enjoy it !
参考资料
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 使用webpack4打造自己的前端工作流
- 从0开始使用webpack搭建react工作流
- 如何使用 Vue CLI 3 加速你的开发工作流?
- [小团队自动化](二) Drone CI使用Vault作为凭据存储 —— 打造自己的CI/CD工作流
- 为什么你应该在项目中使用pyenv+Pipenv:为你的Python项目设置超棒的本地开发工作流之秘籍
- [JWFD开源工作流]JWFD开源工作流-矩阵引擎设计初步
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Four
Scott Galloway / Portfolio / 2017-10-3 / USD 28.00
NEW YORK TIMES BESTSELLER USA TODAY BESTSELLER Amazon, Apple, Facebook, and Google are the four most influential companies on the planet. Just about everyone thinks they know how they got there.......一起来看看 《The Four》 这本书的介绍吧!