30 天精通 Git 版本控管

 主页   资讯   文章   代码   电子书 

第 28 天:了解 GitHub 的 fork 与 pull request 版控流程

我们知道 Git 储存库并没有什麽「权限控管」的概念,因为他是分散式的版本控管系统,当你执行 git clone 之后就会把整份拥有完整版本历史的储存库下载回来,接著你就可以在本地离线的进行开发与建立版本,最后再将变更推送到远端储存库。不过,如果我们只有一份远端储存库的话,这代表大家都有权限将变更推送到远端储存库。因此,GitHub 採用了 forks 与 pull request 的流程,让你可以做到基本的权限控管。

设定 GitHub 专案的权限控管 - 个人帐号

在 GitHub 的个人帐户下,并没有甚麽权限控管的机制,所以只要你授权特定人为协同开发人员 (Collaborators),他就能自由的 Push 与 Pull 专案原始码。

我以我之前在 GitHub 上建立的某个专案为例,专案网址:https://github.com/doggy8088/DataDictionaryCreator

image

进入该网址后,点选右侧选单的 Settings 链接进入:

image

然后就可以加入授权的协同开发人员,这裡要输入的是对方在 GitHub 上的帐号:

image

设定成功的图示如下:

image

但由于你没办法设定更细的 Git 远端储存库权限,所以只要被指派的人,就能够存取完整的 Git 远端储存库,大家都能对任意分支进行推送 (Push)、拉取 (Pull) 或删除分支等动作,要是团队遇上天兵,那可能会是场灾难。

设定 GitHub 专案的权限控管 - 组织帐号

在 GitHub 的组织帐户下,就可以设定人员群组(Teams),你就可以在群组上设定更细的权限,其中包括三种权限:

  • Pull Only (唯读)
  • Push & Pull (可读可写)
  • Push, Pull & Administrative (可读可写以及专案管理权限)

image

设定群组的方法如下:

image

然后选择团队:

image

你也可以点选进入组织设定页面,进一步的来挑选团队成员:

image

image

image

image

image

使用 Fork 功能

英文的 Fork 字面翻译是「叉子」的意思,就好像你刀叉去把食物「叉」起来一样,直接把菜挪放到你自己的盘子裡,我比喻的「菜」就是你要複製的 GitHub 专案,而「盘子」就是你的 GitHub 帐号。

注:老外用刀叉比较多,如果 GitHub 是台湾发展的,这个单字可能会是 Chopsticks (筷子),哈! XD

现在我们以 https://github.com/doggy8088/DataDictionaryCreator 为例,这个专案,你当然没有「写入」权限,只有「唯读」而已。

我现在登入另外一个 GitHub 帐号 ( LearnGitForks ),然后将该专案「叉」到这个帐户自己 GitHub 帐号下:

image

按下去之后,他骨子裡其实就是使用 git clone 来複製该专案到你的 GitHub 帐号下,估计只要十几秒钟就会複製完成,看你複製的专案大小:

image

完成后,在你自己的帐号下,就会有个完全一样的 Git 专案被建立,但会在名称下显示一段 forked from 提示你该专案是来从哪裡複製过来的。

image

因为该专案已经在你自己的帐号下,所以此时你已经可以把该专案当成「自己的远端储存库」在用,完全没有读写权限的问题。

因为 Git 是个分散式版本控管系统,只要你有 fetch 的权限,基本上就可以抓到该版本库的完整版本变更历程。

使用 Fork 过的 Git 远端储存库

在版本控管方面,使用上几乎跟用自己的 Git 远端储存库没什麽两样,而且你也有完整的历史纪录。请记得这份资料是从 https://github.com/doggy8088/DataDictionaryCreator 複製过来的就好。

我们先取得远端储存库回来:

C:\>git clone git@github.com:LearnGitForks/DataDictionaryCreator.git
Cloning into 'DataDictionaryCreator'...
remote: Counting objects: 57, done.
remote: Compressing objects: 100% (45/45), done.
Receiving objects:  71% (41/57), 36.00 KiB | 42.00 KiB/s
Receiving objects: 100% (57/57), 94.08 KiB | 42.00 KiB/s, done.
Resolving deltas: 100% (12/12), done.

C:\>cd DataDictionaryCreator

C:\DataDictionaryCreator>

然后我们建立起一个版本,然后把变更推送回去:

C:\DataDictionaryCreator>echo TEST > test.md

C:\DataDictionaryCreator>git add .

C:\DataDictionaryCreator>git commit -m "Add a test.md for test purpose"
[master b2004b0] Add a test.md for test purpose
 1 file changed, 1 insertion(+)
 create mode 100644 test.md

C:\DataDictionaryCreator>git push
Counting objects: 4, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 285 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To git@github.com:LearnGitForks/DataDictionaryCreator.git
   c29aaab..b2004b0  master -> master

C:\DataDictionaryCreator>

使用 pull request 将变更合併回当初的 GitHub 专案

刚刚我们用 LearnGitForks 身分,把专案从 doggy8088 这边 Fork 回来,然后用 LearnGitForks 的身分 git clone 回本地端,建立版本后再用 git push 推回 GitHub 的 LearnGitForks 下。

现在我们要把储存在 LearnGitForks 帐号下的 DataDictionaryCreator 专案「合併」回 doggy8088 帐号下的 DataDictionaryCreator 专案,这时因为是跨帐号的,所以必须利用 pull request 才能把变更「合併」回去。

注:这裡的 pull request 照字面翻译是「拉取要求」的意思,代表要以 LearnGitForks 的身分,请 doggy8088 把我的变更给拉回去 (git pull),但你不能强迫对方拉(pull),所以必须拜託(request)对方拉,所以才叫做 pull request。

这时,你要用 LearnGitForks 的身分,连到 https://github.com/doggy8088/DataDictionaryCreator 这一页,然后点选 Pull Requests 页籤:

image

然后点选 New pull request 按钮,准备建立一个新的 pull request 项目:

image

接下来你要选择两个版本 (两个 commit 物件),GitHub 才能建立 patch 档案,也才能知道要合併那些东西回去。但你选不到自己 fork 过的版本,因此你要点选 compare across forks

image

然后你就可以选择到自己 fork 过的专案与分支了!不过,这一步要特别注意不要选错,你的版本因为比较新,所以应该要把右边的版本选择成你的,GitHub 才知道从 doggy8088/DataDictionaryCreatormaster 分支,到 LearnGitForks/DataDictionaryCreatormaster 分支,到底发生了那些版本变化。

image

最后你会看到有哪些档案以及哪些地方变更了,然后你就可以按下 Click to create a pull request for this comparison 建立起一个 pull request:

image

最后,我们先看一下右上角有个 Able to merge 的地方,会预先告诉你合併的结果,显示你的版本跟目前的 doggy8088:master 的版本是否有衝突发生。如果都没问题,再输入一些说明文字给原作者 ( doggy8088 ) ,并按下 Send pull request 即可建立完成。

image

Github for Mac;Github for Windows 已增加pull request功能

image

接受 pull request 的要求,确认合併回自己的 GitHub 专案

最后一个步骤,则是让原作者 ( doggy8088 ) 去看有谁传送了一个 pull request 给自己。

现在我重新以 doggy8088 登入 GitHub,并到该专案发现有一个 Pull Requests 进来了:

image

点击进去:

image

最后按下 Merge pull request 即可完成合併工作。

image

今日小结

做到这裡,你应该大致能够了解为什麽会有 fork 与 pull request 的存在,最主要的就是「权限」以及「版本库隔离」的需求。一个上千人的专案 (Linux Kernel),如果所有人都能存取主要的远端储存库,那不是很恐怖吗!

不过在一般企业裡,你不一定要这样做,毕竟操作的步骤确实繁琐了些。实际要怎麽用,就要靠你自己判断了。

参考链接