1. 程式人生 > >Git工作流——Forking工作流

Git工作流——Forking工作流

Forking工作流和前面討論的幾種工作流有根本的不同。這種工作流不是使用單個服務端倉庫作為『中央』程式碼基線,而讓各個開發者都有一個服務端倉庫。這意味著各個程式碼貢獻者有2個Git倉庫而不是1個:一個本地私有的,另一個服務端公開的。

Forking工作流的一個主要優勢是,貢獻的程式碼可以被整合,而不需要所有人都能push程式碼到僅有的中央倉庫中。開發者push到自己的服務端倉庫,而只有專案維護者才能push到正式倉庫。這樣專案維護者可以接受任何開發者的提交,但無需給他正式程式碼庫的寫許可權。

效果就是一個分散式的工作流,能為大型、自發性的團隊(包括了不受信的第三方)提供靈活的方式來安全的協作。也讓這個工作流成為開源專案的理想工作流。

工作方式

和其它的Git工作流一樣,Forking工作流要先有一個公開的正式倉庫儲存在伺服器上。但一個新的開發者想要在專案上工作時,不是直接從正式倉庫克隆,而是fork正式專案在伺服器上建立一個拷貝。

這個倉庫拷貝作為他個人公開倉庫 —— 其它開發者不允許push到這個倉庫,但可以pull到修改(後面我們很快就會看這點很重要)。在建立了自己服務端拷貝之後,和之前的工作流一樣,開發者執行git clone命令克隆倉庫到本地機器上,作為私有的開發環境。

要提交本地修改時,push提交到自己公開倉庫中 —— 而不是正式倉庫中。然後,給正式倉庫發起一個pull request,讓專案維護者知道有更新已經準備好可以集成了。對於貢獻的程式碼,pull request

也可以很方便地作為一個討論的地方。

為了整合功能到正式程式碼庫,維護者pull貢獻者的變更到自己的本地倉庫中,檢查變更以確保不會讓專案出錯,合併變更到自己本地的master分支,然後pushmaster分支到伺服器的正式倉庫中。到此,貢獻的提交成為了專案的一部分,其它的開發者應該執行pull操作與正式倉庫同步自己本地倉庫。

正式倉庫

Forking工作流中,『官方』倉庫的叫法只是一個約定,理解這點很重要。從技術上來看,各個開發者倉庫和正式倉庫在Git看來沒有任何區別。事實上,讓正式倉庫之所以正式的唯一原因是它是專案維護者的公開倉庫。

Forking工作流的分支使用方式

所有的個人公開倉庫實際上只是為了方便和其它的開發者共享分支。各個開發者應該用分支隔離各個功能,就像在

功能分支工作流Gitflow工作流一樣。唯一的區別是這些分支被共享了。在Forking工作流中這些分支會被pull到另一個開發者的本地倉庫中,而在功能分支工作流和Gitflow工作流中是直接被push到正式倉庫中。

示例

專案維護者初始化正式倉庫

和任何使用Git專案一樣,第一步是建立在伺服器上一個正式倉庫,讓所有團隊成員都可以訪問到。通常這個倉庫也會作為專案維護者的公開倉庫。

公開倉庫應該是裸倉庫,不管是不是正式程式碼庫。所以專案維護者會執行像下面的命令來搭建正式倉庫:

ssh [email protected]
git init --bare /path/to/repo.git

BitbucketStash提供了一個方便的GUI客戶端以完成上面命令列做的事。這個搭建中央倉庫的過程和前面提到的工作流完全一樣。如果有現存的程式碼庫,維護者也要push到這個倉庫中。

開發者fork正式倉庫

其它所有的開發需要fork正式倉庫。可以用git clone命令SSH協議連通到伺服器,拷貝倉庫到伺服器另一個位置 —— 是的,fork操作基本上就只是一個服務端的克隆。BitbucketStash上可以點一下按鈕就讓開發者完成倉庫的fork操作。

這一步完成後,每個開發都在服務端有一個自己的倉庫。和正式倉庫一樣,這些倉庫應該是裸倉庫。

開發者克隆自己fork出來的倉庫

下一步,各個開發者要克隆自己的公開倉庫,用熟悉的git clone命令。

在這個示例中,假定用Bitbucket託管了倉庫。記住,如果這樣的話各個開發者需要有各自的Bitbucket賬號,使用下面命令克隆服務端自己的倉庫:

git clone https://[email protected]/user/repo.git

相比前面介紹的工作流只用了一個origin遠端別名指向中央倉庫,Forking工作流需要2個遠端別名 —— 一個指向正式倉庫,另一個指向開發者自己的服務端倉庫。別名的名字可以任意命名,常見的約定是使用origin作為遠端克隆的倉庫的別名(這個別名會在執行git clone自動建立),upstream(上游)作為正式倉庫的別名。

git remote add upstream https://bitbucket.org/maintainer/repo

需要自己用上面的命令建立upstream別名。這樣可以簡單地保持本地倉庫和正式倉庫的同步更新。注意,如果上游倉庫需要認證(比如不是開源的),你需要提供使用者:

git remote add upstream https://[email protected]/maintainer/repo.git

這時在克隆和pull正式倉庫時,需要提供使用者的密碼。

開發者開發自己的功能

在剛克隆的本地倉庫中,開發者可以像其它工作流一樣的編輯程式碼、提交修改新建分支

git checkout -b some-feature
// Edit some code
git commit -a -m "Add first draft of some feature"

所有的修改都是私有的直到push到自己公開倉庫中。如果正式專案已經往前走了,可以用git pull命令獲得新的提交:

git pull upstream master

由於開發者應該都在專門的功能分支上工作,pull操作結果會都是快進合併

開發者釋出自己的功能

一旦開發者準備好了分享新功能,需要做二件事。首先,通過push他的貢獻程式碼到自己的公開倉庫中,讓其它的開發者都可以訪問到。他的origin遠端別名應該已經有了,所以要做的就是:

git push origin feature-branch

這裡和之前的工作流的差異是,origin遠端別名指向開發者自己的服務端倉庫,而不是正式倉庫。

第二件事,開發者要通知專案維護者,想要合併他的新功能到正式庫中。BitbucketStash提供了Pull Request按鈕,彈出表單讓你指定哪個分支要合併到正式倉庫。一般你會想整合你的功能分支到上游遠端倉庫的master分支中。

專案維護者整合開發者的功能

當專案維護者收到pull request,他要做的是決定是否整合它到正式程式碼庫中。有二種方式來做:

  1. 直接在pull request中檢視程式碼
  2. pull程式碼到他自己的本地倉庫,再手動合併

第一種做法更簡單,維護者可以在GUI中檢視變更的差異,做評註和執行合併。但如果出現了合併衝突,需要第二種做法來解決。這種情況下,維護者需要從開發者的服務端倉庫中fetch功能分支,合併到他本地的master分支,解決衝突:

git fetch https://bitbucket.org/user/repo feature-branch
// 檢視變更
git checkout master
git merge FETCH_HEAD

變更整合到本地的master分支後,維護者要push變更到伺服器上的正式倉庫,這樣其它的開發者都能訪問到:

git push origin master

注意,維護者的origin是指向他自己公開倉庫的,即是專案的正式程式碼庫。到此,開發者的貢獻完全整合到了專案中。

開發者和正式倉庫做同步

由於正式程式碼庫往前走了,其它的開發需要和正式倉庫做同步:

git pull upstream master

下一站

如果你之前是使用SVNForking工作流可能看起來像是一個激進的正規化切換(paradigm shift)。但不要害怕,這個工作流實際上就是在功能分支工作流之上引入另一個抽象層。不是直接通過單箇中央倉庫來分享分支,而是把貢獻程式碼釋出到開發者自己的服務端倉庫中。

示例中解釋了,一個貢獻如何從一個開發者流到正式的master分支中,但同樣的方法可以把貢獻整合到任一個倉庫中。比如,如果團隊的幾個人協作實現一個功能,可以在開發之間用相同的方法分享變更,完全不涉及正式倉庫。

這使得Forking工作流對於鬆散組織的團隊來說是個非常強大的工具。任一開發者可以方便地和另一開發者分享變更,任何分支都能有效地合併到正式程式碼庫中。