四種常見 Git 工做流比較

BY 童仲毅(geeeeeeeeek@github)git

這是一篇在原文(BY atlassian)基礎上演繹的譯文。除非另行註明,頁面上全部內容採用知識共享-署名(CC BY 2.5 AU)協議共享。github

多種多樣的工做流使得在項目中實施Git時變得難以選擇。這份教程提供了一個出發點,調查企業團隊最多見的Git工做流。緩存

閱讀的時候,請記住工做流應該是一種規範而不是金科玉律。咱們但願向你展現全部工做流,讓你融會貫通,因地制宜。安全

這份教程討論了下面四種工做流:服務器

中心化的工做流

Git Workflows: SVN-style Workflow

過渡到分佈式分版本控制系統看起來是個使人恐懼的任務,但你沒必要爲了利用Git的優勢而改變你現有的工做流。你的團隊仍然能夠用之前SVN的方式開發項目。markdown

然而,使用Git來驅動你的開發工做流顯示出了一些SVN沒有的優勢。首先,它讓每一個開發者都有了本身 本地 的完整項目副本。隔離的環境使得每一個開發者的工做獨立於項目的其它修改——他們能夠在本身的本地倉庫中添加提交,徹底無視上游的開發,直到須要的時候。app

第二,它讓你接觸到了Git魯棒的分支和合並模型。和SVN不一樣,Git分支被設計爲一種故障安全的機制,用來在倉庫之間整合代碼和共享更改。框架

如何工做

和Subversion同樣,中心化的工做流將中央倉庫做爲項目中全部修改的惟一入口。和trunk不一樣,默認的開發分支叫作master,全部更改都被提交到這個分支。這種工做流不須要master以外的其它分支。ssh

開發者將中央倉庫克隆到本地後開始工做。在他們的本地項目副本中,他們能夠像SVN同樣修改文件和提交更改;不過,這些新的提交被保存在 本地 ——它們和中央倉庫徹底隔離。這使得開發者能夠將和上游的同步推遲到他們方便的時候。分佈式

爲了向官方項目發佈修改,開發者將他們的本地master分支「推送」到中央倉庫。這一步等同於svn commit,除了Git添加的是全部不在中央master分支上的本地提交。

Central and local repositories

管理衝突

中央倉庫表明官方項目,所以它的提交歷史應該被視做神聖不可更改的。若是開發者的本地提交和中央倉庫分叉了,Git會拒絕將他們的修改推送上去,由於這會覆蓋官方提交。

Managing Conflicts

在開發者發佈他們的功能以前,他們須要fetch更新的中央提交,在它們之上rebase本身的更改。這就像是:「我想要在其餘人的工做進展之上添加個人修改。」它會產生完美的線性歷史,就像和傳統的SVN工做流同樣。

若是本地修改和上游提交衝突時,Git會暫停rebase流程,給你機會手動解決這些衝突。Git很讚的一點是,它將git statusgit add命令同時用來生成提交和解決合併衝突。這使得開發者可以垂手可得地管理他們的合併。另外,若是他們改錯了什麼,Git讓他們輕易地退出rebase過程,而後重試(或者找人幫忙)。

栗子

讓咱們一步步觀察一個普通的小團隊是如何使用這種工做流協做的。咱們有兩位開發者,John和Mary,分別在開發兩個功能,他們經過中心化的倉庫共享代碼。

一人初始化了中央倉庫

Git Workflows: Initialize Central Bare Repository

首先,須要有人在服務器上建立中央倉庫。若是這是一個新項目,你能夠初始化一個空的倉庫。否則,你須要導入一個已經存在的Git或SVN項目。

中央倉庫應該永遠是裸倉庫(沒有工做目錄),能夠這樣建立:

ssh user@host git init --bare /path/to/repo.git

但確保你使用的SSH用戶名user、服務器host的域名或IP地址、儲存倉庫的地址/path/to/repo.git是有效的。注意.git約定俗成地出如今倉庫名的後面,代表這是一個裸倉庫。

全部人將倉庫克隆到本地

Git Workflows: Clone Central Repo

接下來,每一個開發者在本地建立一份完整項目的副本。使用git clone命令:

git clone ssh://user@host/path/to/repo.git

當你克隆倉庫時,Git自動添加了一個名爲origin的遠程鏈接,指向「父」倉庫,以便你之後和這個倉庫交換數據。

John在開發他的功能

Git Workflows: Edit Stage Commit Feature Process

在他的本地倉庫中,John能夠用標準的Git提交流程開發功能:編輯、緩存、提交。若是你對緩存區還不熟悉,你也能夠不用記錄工做目錄中每次的變化。因而你建立了一個高度集中的提交,即便你已經在本地作了不少修改。

git status # 查看倉庫狀態
git add <some-file> # 緩存一個文件
git commit # 提交一個文件</some-file>

記住,這些命令建立的是本地提交,John能夠周而復始地重複這個過程,而不用考慮中央倉庫。對於龐大的功能,須要切成更簡單、原子化的片斷時,這個特性就頗有用。

Mary在開發她的功能

Git Workflows: Edit Stage Commit Feature

同時,Mary在她本身的本地倉庫用相同的編輯/緩存/提交流程開發她的功能。和John同樣,她不須要關心中央倉庫的進展,她也 徹底 不關心John在他本身倉庫中作的事,由於全部本地倉庫都是私有的。

John發佈了他的功能

Git Workflows: Publish Feature

一旦John完成了他的功能,他應該將本地提交發布到中央倉庫,這樣其餘項目成員就能夠訪問了。他可使用git push命令,就像:

git push origin master

記住,origin是John克隆中央倉庫時指向它的遠程鏈接。master參數告訴Git試着將originmaster分支變得和他本地的master分支同樣。中央倉庫在John克隆以後尚未進展,所以這個推送如他所願,沒有產生衝突。

Mary試圖發佈她的功能

Git Workflows: Push Command Error

John已經成功地將他的更改發佈到了中央倉庫上,看看當Mary試着將她的功能推送到上面時會發生什麼。她可使用同一個推送命令:

git push origin master

可是,她的本地歷史和中央倉庫已經分叉了,Git會拒絕這個請求,並顯示一段冗長的錯誤信息:

error: failed to push some refs to '/path/to/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Git防止Mary覆蓋官方的修改。她須要將John的更新拉取到她的倉庫,和她的本地修改整合後,而後重試。

Mary在John的提交之上rebase

Git Workflows: Git Pull Rebase

Mary可使用git pull來將上游修改併入她的倉庫。這個命令和svn update很像——它拉取整個上游提交歷史到Mary的本地倉庫,並和她的本地提交一塊兒整合:

git pull --rebase origin master

--rebase選項告訴Git,在同步了中央倉庫的修改以後,將Mary全部的提交移到master分支的頂端,以下圖所示:

Rebasing to Master

若是你忽略這個選項拉取一樣會成功,只不過你每次和中央倉庫同步時都會多出一個「合併提交」。在這種工做流中,rebase和生成一個合併提交相比,老是一個更好的選擇。

Mary解決了合併衝突

Git Workflows: Rebasing on Commits

Rebase的工做是將每一個本地提交一個個轉移到更新後的master分支。也就是說,你能夠一個個提交分別解決合併衝突,而不是在一個龐大的合併提交中解決。它會讓你的每一個提交保持專一,並得到一個乾淨的項目歷史。另外一方面,你更容易發現bug是在哪引入的,若是有必要的話,用最小的代價回滾這些修改。

若是Mary和John開發的功能沒有關聯,rebase的過程不太可能出現衝突。但若是出現衝突時,Git在當前提交會暫停rebase,輸出下面的信息,和一些相關的指令:

CONFLICT (content): Merge conflict in <some-file>

Conflict Resolution

Git的優勢在於 每一個人 都能解決他們本身的合併衝突。在這個例子中,Mary只需運行一下git status就能夠發現問題是什麼。衝突的文件會出如今未合併路徑中:

# Unmerged paths:
# (use "git reset HEAD <some-file>..." to unstage)
# (use "git add/rm <some-file>..." as appropriate to mark resolution)
#
# both modified: <some-file>

接下來,修改這些文件。若是她對結果滿意了,和往常同樣緩存這些文件,而後讓git rebase完成接下來的工做:

git add <some-file>
git rebase --continue

就是這樣。Git會繼續檢查下個提交,對衝突的提交重複這個流程。

若是你這時候發現不知道本身作了什麼,不要驚慌。只要運行下面的命令,你就會回到開始以前的狀態:

git rebase --abort

Mary成功發佈了她的分支

Git Workflows: Synchronize Central Repo

在她和中央倉庫同步以後,Mary能夠成功地發佈她的修改:

git push origin master

接下來該怎麼作

正如你所見,使用一丟丟Git命令來複制一套傳統的Subversion開發環境也是可行的。這對於從SVN轉變而來的團隊來講很棒,但這樣沒有利用到Git分佈式的本質。

若是你的團隊已經習慣了中心化的工做流,但但願提升協做效率,那麼探索Feature分支工做流的好處是徹底值當的。每一個功能在專門的獨立分支上進行,在代碼併入官方項目以前就能夠啓動圍繞新修改的深度討論。

Feature分支的工做流

Feature Branch Workflow

一旦你掌握了中心化工做流的使用姿式,在你的開發流程中添加功能分支是一個簡單的方式,來促進協做和開發者之間的交流。這種封裝使得多個開發者專一本身的功能而不會打擾主代碼庫。它還保證master分支永遠不會包含損壞的代碼,給持續集成環境帶來了是很大的好處。

封裝功能的開發使得pull request的使用成爲可能,用來啓動圍繞一個分支的討論。它給了其餘開發者在功能併入主項目以前參與決策的機會。或者,若是你開發功能時卡在一半,你能夠發起一個pull request,向同事尋求建議。重點是,pull request使得你的團隊在評論其餘人的工做時變得很是簡單。

如何工做

Feature分支工做流一樣使用中央倉庫,master一樣表明官方的項目歷史。可是,與其直接提交在本地的master分支,開發者每次進行新的工做時建立一個新的分支。Feature分支應該包含描述性的名稱,好比animated-menu-items(菜單項動畫)或issue-#1061。每一個分支都應該有一個清晰、高度集中的目的。

Git在技術上沒法區別master和功能分支,因此開發者能夠在feature分支上編輯、緩存、提交,就和中心化工做流中同樣。

此外,feature分支能夠(也應該)被推送到中央倉庫。這使得你和其餘開發者共享這個功能,而又不改變官方代碼。既然master只是一個「特殊」的分支,在中央倉庫中儲存多個feature分支不會引出什麼問題。固然了,這也是備份每一個開發者本地提交的好辦法。

Pull Request

除了隔離功能開發以外,分支使得經過pull request討論修改爲爲可能。一旦有人完成了一個功能,他們不會當即將它併入master。他們將feature分支推送到中央服務器上,發佈一個pull request,請求將他們的修改併入master。這給了其餘開發者在修改併入主代碼庫以前審查的機會。

代碼審查是pull request的主要好處,但他們事實上被設計爲成爲討論代碼的通常場所。你能夠把pull request看做是專一某個分支的討論版。也就是說他們能夠用於開發流程以前。好比,一個開發者在某個功能上須要幫助,他只需發起一個pull request。感興趣的小夥伴會自動收到通知,看到相關提交中的問題。

一旦pull request被接受了,發佈功能的行爲和中心化的工做流是同樣的。首先,肯定你本地的master和上游的master已經同步。而後,將feature分支併入master,將更新的master推送回中央倉庫。

栗子

下面這個🌰演示了代碼審查使用到的pull request,但記住pull request有多種用途。

Mary開始了一個新功能

New Feature Branch

在她開始開發一個功能以前,Mary須要一個獨立的分支。她能夠用下面的命令建立新分支

git checkout -b marys-feature master

一個基於master、名爲marys-feature的分支將會被checkout,-b標記告訴Git在分支不存在時建立它。在這個分支上,Mary和往常同樣編輯、緩存、提交更改,用足夠多的提交來構建這個功能:

git status
git add <some-file>
git commit

Mary去吃飯了

Git Workflows: Feature Commits

Mary在早上給她的功能添加了一些提交。在她去吃午餐前,將她的分支推送到中央倉庫是個不錯的想法。這是一種方便的備份,但若是Mary和其餘開發者一塊兒協做,他們也能夠看到她的初始提交了。

git push -u origin marys-feature

這個命令將marys-feature推送到中央倉庫(origin),-u標記將它添加爲遠程跟蹤的分支。在設置完跟蹤的分支以後,Mary調用不帶任何參數的git push來推送她的功能。

Mary完成了她的工做

Git Workflows: Pull Request

當Mary吃完午餐回來,她完成了她的功能。在併入master以前,她須要發佈一個pull request,讓其餘的團隊成員知道她所作的工做。但首先,她應該保證中央倉庫包含了她最新的提交:

git push

而後,她在她的Git界面上發起了一個pull request,請求將marys-feature合併進master,團隊成員會收到自動的通知。Pull request的好處是,評論顯示在相關的提交正下方,方便討論特定的修改。

Bill收到了pull request

Git Workflows: Feature Pull Requests

Bill收到了pull request,而且查看了marys-feature。他決定在併入官方項目以前作一些小修改,經過pull request和Mary進行了溝通。

Mary做了修改

Git Workflows: Central Repository Push

爲了作這些更改,Mary重複了以前建立功能時相同的流程,她編輯、緩存、提交、將更新推送到中央倉庫。她全部的活動顯示在pull request中,Bill能夠一直評論。

若是Bill想要的話,也能夠將marys-featurepull到他本身的本地倉庫,繼續工做。後續的任何提交都會顯示在pull request上。

Mary發佈了她的功能

Merging a Feature Branch

一旦Bill準備接受這個pull request,某我的(Bill或者Mary均可)須要將功能併入穩定的項目:

git checkout master
git pull
git pull origin marys-feature
git push

首先,無論是誰在執行合併,都要保證他們的master分支是最新的。而後,運行git pull origin marys-feature合併中央倉庫的marys-feature副本。你也可使用簡單的git merge marys-feature,但以前的命令保證你拉取下來的必定是功能分支最新的版本。最後,更新的master須要被推送回origin

這個過程致使了一個合併提交。一些開發者喜歡它,由於它是功能和其他代碼合併的標誌。但,若是你但願獲得線性的歷史,你能夠在執行merge以前將功能rebase到master分支的頂端,產生一個快速向前的合併。

一些界面會自動化接受pull request的流程,只需點擊一下「Merge Pull Request」。若是你的沒有的話,它至少在合併以後應該能夠自動地關閉pull request。

同時,John以一樣的方式工做着

Mary和Bill一塊兒開發marys-feature,在pull request上討論的同時,John還在開發他本身的feature分支。經過將功能用不一樣分支隔離開來,每一個人能夠獨立地工做,但很容易和其餘開發者共享修改。

接下來該怎麼作

爲了完全瞭解Github上的功能分支,你應該查看使用分支一章。如今,你應該已經看到了功能分支極大地加強了中心化工做流中單一master分支的做用。除此以外,功能分支還便利了pull request的使用,在版本控制界面上直接討論特定的提交。Gitflow工做流是管理功能開發、發佈準備、維護的常見模式。

Gitflow工做流

Gitflow Workflow

下面的Gitflow工做流一節源於nvie網站上的做者Vincent Driessen。

Gitflow工做流圍繞項目發佈定義了一個嚴格的分支模型。有些地方比功能分支工做流更復雜,爲管理大型項目提供了魯棒的框架。

和功能分支工做流相比,這種工做流沒有增長任何新的概念或命令。它給不一樣的分支指定了特定的角色,定義它們應該如何、何時交流。除了功能分支以外,它還爲準備發佈、維護髮布、記錄發佈分別使用了單獨的分支。固然,你還能享受到功能分支工做流帶來的全部好處:pull request、隔離實驗和更高效的協做。

如何工做

Gitflow工做流仍然使用中央倉庫做爲開發者溝通的中心。和其餘工做流同樣,開發者在本地工做,將分支推送到中央倉庫。惟一的區別在於項目的分支結構。

歷史分支

和單獨的master分支不一樣,這種工做流使用兩個分支來記錄項目歷史。master分支儲存官方發佈歷史,develop分支用來整合功能分支。同時,這還方便了在master分支上給全部提交打上版本號標籤。

Historical Branches

工做流剩下的部分圍繞這兩個分支的差異展開。

功能分支

每一個新功能都放置在本身的分支中,能夠在備份/協做時推送到中央倉庫。可是,與其合併到master,功能分支將開發分支做爲父分支。當一個功能完成時,它將被合併回develop。功能永遠不該該直接在master上交互。

Feature Branches

注意,功能分支加上develop分支就是咱們以前所說的功能分支工做流。可是,Gitflow工做流不止於此。

發佈分支

Release Branches

一旦develop分支的新功能足夠發佈(或者預先肯定的發佈日期即將到來),你能夠從develop分支fork一個發佈分支。這個分支的建立開始了下個發佈週期,只有和發佈相關的任務應該在這個分支進行,如修復bug、生成文檔等。一旦準備好了發佈,發佈分支將合併進master,打上版本號的標籤。另外,它也應該合併回develop,後者可能在發佈啓動以後有了新的進展。

使用一個專門的分支來準備發佈確保一個團隊完善當前的發佈,其餘團隊能夠繼續開發下一個發佈的功能。它還創建了清晰的開發階段(好比說,「這周咱們準備4.0版本的發佈」,而咱們在倉庫的結構中也能看到這個階段)。

一般咱們約定:

  • develop建立分支
  • 合併進master分支
  • 命名規範release-* or release/*

維護分支

Maintenance Branches

維護或者「緊急修復」分支用來快速給產品的發佈打上補丁。這是惟一能夠從master上fork的分支。一旦修復完成了,它應該被併入masterdevelop分支(或者當前的發佈分支),master應該打上更新的版本號的標籤。

有一個專門的bug修復開發線使得你的團隊可以處理issues,而不打斷其餘工做流或是要等到下一個發佈週期。你能夠將維護分支看做在master分支上工做的臨時發佈分支。

栗子

下面的栗子演示了這種工做流如何用來管理髮布週期。假設你已經建立了中央倉庫。

建立一個開發分支

Create a Develop Branch

你要作的第一步是爲默認的master分支建立一個互補的develop分支。最簡單的辦法是在本地建立一個空的develop分支,將它推送到服務器上:

git branch develop
git push -u origin develop

這個分支將會包含項目中全部的歷史,而master將包含不徹底的版本。其餘開發者應該將中央倉庫克隆到本地,建立一個分支來追蹤develop分支:

git clone ssh://user@host/path/to/repo.git
git checkout -b develop origin/develop

如今全部人都有了一份歷史分支的本地副本。

Mary和John開始了新功能

New Feature Branches

咱們的栗子從John和Mary在不一樣分支上工做開始。他們都要爲本身的功能建立單獨的分支。他們的功能分支都應該基於develop,而不是master

git checkout -b some-feature develop

他們都使用「編輯、緩存、提交」的通常約定來向功能分支添加提交:

git status
git add <some-file>
git commit

Mary完成了她的功能

Merging a Feature Branch

在添加了一些提交以後,Mary確信她的功能以及準備好了。若是她的團隊使用pull request,如今正是發起pull request的好時候,請求將她的功能併入develop分支。不然,她能夠向下面同樣,將它併入本地的develop分支,推送到中央倉庫:

git pull origin develop
git checkout develop
git merge some-feature
git push
git branch -d some-feature

第一個命令在嘗試併入功能分支以前確保develop分支已經是最新。注意,功能毫不該被直接併入master。衝突的處理方式和中心化工做流相同。

Mary開始準備發佈

Preparing a Release

當John仍然在他的功能分支上工做時,Mary開始準備項目的第一個官方發佈。和開發功能同樣,她新建了一個分支來封裝發佈的準備工做。這也正是發佈的版本號建立的一步:

git checkout -b release-0.1 develop

這個分支用來整理提交,充分測試,更新文檔,爲即將到來的發佈作各類準備。它就像是一個專門用來完善發佈的功能分支。

一旦Mary建立了這個分支,推送到中央倉庫,此次發佈的功能便被鎖定了。不在develop分支中的功能將被推遲到下個發佈週期。

Mary完成了她的發佈

Merging Release into Master

一旦發佈準備穩妥,Mary將它併入masterdevelop,而後刪除發佈分支。合併回develop很重要,由於可能已經有關鍵的更新添加到了發佈分支上,而開發新功能須要用到它們。一樣的,若是Mary的團隊重視代碼審查,如今將是發起pull request的完美時機。

git checkout master
git merge release-0.1
git push
git checkout develop
git merge release-0.1
git push
git branch -d release-0.1

發佈分支是功能開發(develop)和公開發布(master)之間的過渡階段。不論何時將提交併入master時,你應該爲提交打上方便引用的標籤:

git tag -a 0.1 -m "Initial public release" master
git push --tags

Git提供了許多鉤子,即倉庫中特定事件發生時被執行的腳本。當你向中央倉庫推送master分支或者標籤時,你能夠配置一個鉤子來自動化構建公開發布。

終端用戶發現了一個bug

Maintenance Branch

正式發佈以後,Mary回過頭來和John一塊兒爲下一個發佈開發功能。這時,一個終端用戶開了一個issue抱怨說當前發佈中存在一個bug。爲了解決這個bug,Mary(或John)從master建立了一個維護分支,用幾個提交修復這個issue,而後直接合並回master

git checkout -b issue-#001 master
# Fix the bug
git checkout master
git merge issue-#001
git push

和發佈分支同樣,維護分支包含了develop中須要的重要更新,所以Mary一樣須要執行這個合併。接下來,她能夠刪除這個分支了:

git checkout develop
git merge issue-#001
git push
git branch -d issue-#001

接下來該怎麼作

如今,但願你已經很熟悉中心化的工做流功能分支工做流和Gitflow工做流。你應該已經能夠抓住本地倉庫、推送/拉取模式,和Git魯棒的分支和合並模型的無限潛力。

請記住,教程中呈現的工做流只是可行的實踐——而非工做中使用Git的金科玉律。所以,盡情地取其精華,去其糟粕吧。不變的是要讓Git爲你所用,而不是相反。

Fork工做流

Fork工做流和教程中討論的其它工做流大相徑庭。與其使用惟一的服務端倉庫做爲」中央「代碼庫,它給予 每一個 開發者一個服務端倉庫。也就是說每一個貢獻者都有兩個Git倉庫,而不是一個:一個私有的本地倉庫和一個公開的服務端倉庫。

Git Workflows: Forking

Fork工做流的主要優勢在於貢獻能夠輕易地整合進項目,而不須要每一個人都推送到單一的中央倉庫。開發者推送到他們 本身的 服務端倉庫,只有項目管理者能夠推送到官方倉庫。這使得管理者能夠接受任何開發者的提交,卻不須要給他們中央倉庫的權限。

結論是,這種分佈式的工做流爲大型、組織性強的團隊(包括不可信的第三方)提供了安全的協做方式。它同時也是開源項目理想的工做流。

如何工做

和其它Git工做流同樣,Fork工做流以一個儲存在服務端的官方公開項目開場。但新的開發者想參與項目時,他們不直接克隆官方項目。

取而代之地,他們fork一份官方項目,在服務端建立一份副本。這份新建的副本做爲他們私有的公開倉庫——沒有其餘開發者能夠在上面推送,但他們能夠從上面拉取修改(在後面咱們會討論爲何這一點很重要)。在他們建立了服務端副本以後,開發者執行git clone操做,在他們的本地機器上覆制一份。這是他們私有的開發環境,正如其餘工做流中同樣。

當他們準備好發佈本地提交時,他們將提交推送到本身的公開倉庫——而非官方倉庫。而後,他們向主倉庫發起一個pull request,讓項目維護者知道一個更新作好了合併的準備。若是貢獻的代碼有什麼問題的話,Pull request能夠做爲一個方便的討論版。

我爲了將功能併入官方代碼庫,維護者將貢獻者的修改拉取到他們的本地倉庫,確保修改不會破壞項目,將它合併到本地的master分支,而後將master分支推送到服務端的官方倉庫。貢獻如今已經是項目的一部分,其餘開發者應該從官方倉庫拉取並同步他們的本地倉庫。

中央倉庫

「官方」倉庫這個概念在Fork工做流中只是一個約定,理解這一點很重要。從技術的角度,Git並看不出每一個開發者和官方的公開倉庫有什麼區別。事實上,官方倉庫惟一官方的緣由是,它是項目維護者的倉庫。

Fork工做流中的分支

全部這些我的的公開倉庫只是一個在開發者之間共享分支的約定。每一個人仍然可使用分支來隔離功能,就像在功能分支工做流Gitflow工做流中同樣。惟一的區別在於這些分支是如何開始的。在Fork工做流中,它們從另外一個開發者的本地倉庫拉取而來,而在功能分支和Gitflow分支它們被推送到官方倉庫。

栗子

項目維護者初始化了中央倉庫

Forking Workflow: Shared Repository

和任何基於Git的項目同樣,第一步是在服務端建立一個能夠被全部項目成員訪問到的官方倉庫。通常來講,這個倉庫同時仍是項目維護者的公開倉庫。

公開的倉庫應該永遠是裸的,無論它們是否表明官方代碼庫。因此項目維護者應該運行下面這樣的命令來設置官方倉庫:

ssh user@host
git init --bare /path/to/repo.git

Github同時提供了一個圖形化界面來替代上面的操做。這和教程中其它工做流設置中央倉庫的流程徹底一致。若是有必要的話,項目維護者應該將已有的代碼庫推送到這個倉庫中。

開發者fork倉庫

Forking Workflow: Forking the official repository.

接下來,全部開發者須要fork官方倉庫。你能夠用SSH到服務器,運行git clone將它複製到服務器的另外一個地址——fork其實只是服務端的clone。但一樣地,Github上開發者只需點一點按鈕就能夠fork倉庫。

在這步以後,每一個開發者應該都有了本身的服務端倉庫。像官方倉庫同樣,全部這些倉庫都應該是裸倉庫。

開發者將fork的倉庫克隆到本地

Forking Workflow: Cloning the forked repositories

接下來開發者須要克隆他們本身的公開倉庫。他們能夠用熟悉的git clone命令來完成這一步。

咱們的栗子假設使用他們使用Github來託管倉庫。記住,在這種狀況下,每一個開發者應該有他們本身的Github帳號,應該用下面的命令克隆服務端倉庫:

git clone https://user@github.com/user/repo.git

而教程中的其餘工做流使用單一的origin遠程鏈接,指向中央倉庫,Fork工做流須要兩個遠程鏈接,一個是中央倉庫,另外一個是開發者我的的服務端倉庫。你能夠給這些遠端取任何名字,約定的作法是將origin做爲你fork後的倉庫的遠端(運行git clone是會自動建立)和upstream做爲官方項目。

git remote add upstream https://github.com/maintainer/repo

你須要使用上面的命令來建立上游倉庫的遠程鏈接。它使得你輕易地保持本地倉庫和官方倉庫的進展同步。注意若是你的上游倉庫開啓了認證(好比它沒有開源),你須要提供一個用戶名,就像這樣:

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

它須要用戶從官方代碼庫克隆或拉取以前提供有效的密碼。

開發者進行本身的開發

Forking Workflow: Developers work on features

在他們剛克隆的本地倉庫中,開發者能夠編輯代碼、提交更改,和其它分支中同樣建立分支

git checkout -b some-feature
# 編輯代碼
git commit -a -m "Add first draft of some feature"

他們全部的更改在推送到公開倉庫以前都是徹底私有的。並且,若是官方項目已經向前進展了,他們能夠用git pull獲取新的提交:

git pull upstream master

由於開發者應該在專門的功能分支開發,這通常會產生一個快速向前的合併

開發者發佈他們的功能

Forking Workflow: Developers publish features

一旦開發者準備好共享他們的新功能,他們須要作兩件事情。第一,他們必須將貢獻的代碼推送到本身的公開倉庫,讓其餘開發者可以訪問到。他們的origin遠端應該已經設置好了,因此他們只須要:

git push origin feature-branch

這和其餘工做流不一樣之處在於,origin遠端指向開發者我的的服務端倉庫,而不是主代碼庫。

第二,他們須要通知項目維護者,他們想要將功能併入官方代碼庫。Github提供了一個「New Pull Request」按鈕,跳轉到一個網頁,讓你指明想要併入主倉庫的分支。通常來講,你但願將功能分支併入上游遠端的master分支。

項目維護者整合他們的功能

Forking Workflow: Integrate Features

當項目維護者收到pull request時,他們的工做是決定是否將它併入官方的代碼庫。他們可使用下面兩種方式之一:

  1. 直接檢查pull request中檢查代碼
  2. 將代碼拉取到本地倉庫而後手動合併

第一個選項更簡單,讓維護者查看修改先後的差別,在上面評論,而後經過圖形界面執行合併。然而,若是pull request會致使合併衝突,第二個選項就有了必要。在這個狀況中,維護者須要從開發者的服務端倉庫fetch功能分支,合併到他們本地的master分支,而後解決衝突:

git fetch https://bitbucket.org/user/repo feature-branch
# 檢查修改
git checkout master
git merge FETCH_HEAD

一旦修改被整合進本地的master,維護者須要將它推送到服務器上的官方倉庫,這樣其餘開發者也能夠訪問它:

git push origin master

記住,維護者的origin指向他們的公開倉庫,也就是項目的官方代碼庫。開發者的貢獻如今徹底併入了項目。

開發者和中央倉庫保持同步

Forking Workflow: Synchronize with the official repository

由於主代碼庫已經取得了新的進展,其餘開發者應該和官方倉庫同步:

git pull upstream master

接下來該怎麼作

若是你從SVN遷移而來,Fork工做流看上去是一個比較大的轉變。但不要懼怕——它只是在Feature分支工做流之上引入了一層抽象。貢獻的代碼發佈到開發者在服務端本身的倉庫,而不是在惟一的中央倉庫中直接共享分支。

這篇文章解釋了一次代碼貢獻是如何從一個開發者流入官方的master分支的,但相同的方法能夠用在將代碼貢獻整合進任何倉庫。好比,若是你團隊的一部分紅員在一個特定功能上協做,他們能夠用本身約定的行爲共享修改——而不改變主倉庫。

這使得Fork工做流對於鬆散的團隊來講是個很是強大的工具。任何開發者均可以垂手可得地和其餘開發者共享修改,任何分支都能高效地併入主代碼庫。

相關文章
相關標籤/搜索