天天看點

四種常用的Git工作流過程分析

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

閱讀的時候,請記住工作流應該是一種規範而不是金科玉律。我們希望向你展示所有工作流,讓你融會貫通,因地制宜。

這份教程讨論了下面四種工作流:

1.中心化的工作流

2.基于功能分支的工作流

3.Gitflow工作流

4.Fork工作流

中心化的工作流

過渡到分布式分版本控制系統看起來是個令人恐懼的任務,但你不必為了利用Git的優點而改變你現有的工作流。你的團隊仍然可以用以前SVN的方式開發項目。

然而,使用Git來驅動你的開發工作流顯示出了一些SVN沒有的優點。首先,它讓每個開發者都有了自己 本地 的完整項目副本。隔離的環境使得每個開發者的工作獨立于項目的其它修改——他們可以在自己的本地倉庫中添加送出,完全無視上遊的開發,直到需要的時候。

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

如何工作

和Subversion一樣,中心化的工作流将中央倉庫作為項目中所有修改的唯一入口。和trunk

不同,預設的開發分支叫做master,所有更改都被送出到這個分支。這種工作流不需要master之外的其它分支。

開發者将中央倉庫克隆到本地後開始工作。在他們的本地項目副本中,他們可以像SVN一樣修改檔案和送出更改;不過,這些新的送出被儲存在 本地 ——它們和中央倉庫完全隔離。這使得開發者可以将和上遊的同步推遲到他們友善的時候。

為了向官方項目釋出修改,開發者将他們的本地master分支“推送”到中央倉庫。這一步等同于svn commit,除了Git添加的是所有不在中央master分支上的本地送出。

管理沖突

中央倉庫代表官方項目,是以它的送出曆史應該被視作神聖不可更改的。如果開發者的本地送出和中央倉庫分叉了,Git會拒絕将他們的修改推送上去,因為這會覆寫官方送出。

在開發者釋出他們的功能之前,他們需要fetch更新的中央送出,在它們之上rebase自己的更改。這就像是:“我想要在其他人的工作進展之上添加我的修改。”它會産生完美的線性曆史,就像和傳統的SVN工作流一樣。

如果本地修改和上遊送出沖突時,Git會暫停rebase流程,給你機會手動解決這些沖突。Git很贊的一點是,它将git status

和git add

指令同時用來生成送出和解決合并沖突。這使得開發者能夠輕而易舉地管理他們的合并。另外,如果他們改錯了什麼,Git讓他們輕易地退出rebase過程,然後重試(或者找人幫忙)。

栗子

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

一人初始化了中央倉庫

首先,需要有人在伺服器上建立中央倉庫。如果這是一個新項目,你可以初始化一個空的倉庫。不然,你需要導入一個已經存在的Git或SVN項目。

中央倉庫應該永遠是裸倉庫(沒有工作目錄),可以這樣建立:

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

但確定你使用的SSH使用者名user、伺服器host的域名或IP位址、儲存倉庫的位址/path/to/repo.git是有效的。注意.git約定俗成地出現在倉庫名的後面,表明這是一個裸倉庫。

所有人将倉庫克隆到本地

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

指令:

git clone ssh://[email protected]/path/to/repo.git

John在開發他的功能

在他的本地倉庫中,John可以用标準的Git送出流程開發功能:編輯、緩存、送出。如果你對緩存區還不熟悉,你也可以不用記錄工作目錄中每次的變化。于是你建立了一個高度集中的送出,即使你已經在本地做了很多修改。

git status # 檢視倉庫狀态

git add # 緩存一個檔案

git commit # 送出一個檔案

記住,這些指令建立的是本地送出,John可以周而複始地重複這個過程,而不用考慮中央倉庫。對于龐大的功能,需要切成更簡單、原子化的片段時,這個特性就很有用。

Mary在開發她的功能

同時,Mary在她自己的本地倉庫用相同的編輯/緩存/送出流程開發她的功能。和John一樣,她不需要關心中央倉庫的進展,她也 完全 不關心John在他自己倉庫中做的事,因為所有本地倉庫都是私有的。

John釋出了他的功能

一旦John完成了他的功能,他應該将本地送出釋出到中央倉庫,這樣其他項目成員就可以通路了。他可以使用git push指令,就像:

git push origin master

記住,origin是John克隆中央倉庫時指向它的遠端連接配接。master參數告訴Git試着将origin的master分支變得和他本地的master分支一樣。中央倉庫在John克隆之後還沒有進展,是以這個推送如他所願,沒有産生沖突。

Mary試圖釋出她的功能

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

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

Mary可以使用git pull

來将上遊修改并入她的倉庫。這個指令和svn update

很像——它拉取整個上遊送出曆史到Mary的本地倉庫,并和她的本地送出一起整合:

git pull --rebase origin master

–rebase選項告訴Git,在同步了中央倉庫的修改之後,将Mary所有的送出移到master分支的頂端,如下圖所示(圖略)。

如果你忽略這個選項拉取同樣會成功,隻不過你每次和中央倉庫同步時都會多出一個“合并送出”。在這種工作流中,rebase和生成一個合并送出相比,總是一個更好的選擇。

Mary解決了合并沖突

Rebase的工作是将每個本地送出一個個轉移到更新後的master分支。也就是說,你可以一個個送出分别解決合并沖突,而不是在一個龐大的合并送出中解決。它會讓你的每個送出保持專注,并獲得一個幹淨的項目曆史。另一方面,你更容易發現bug是在哪引入的,如果有必要的話,用最小的代價復原這些修改。

如果Mary和John開發的功能沒有關聯,rebase的過程不太可能出現沖突。但如果出現沖突時,Git在目前送出會暫停rebase,輸出下面的資訊,和一些相關的指令:

CONFLICT (content): Merge conflict in

Git的優點在于 每個人 都能解決他們自己的合并沖突。在這個例子中,Mary隻需運作一下git status

就可以發現問題是什麼。沖突的檔案會出現在未合并路徑中:

Unmerged paths:

(use “git reset HEAD …” to unstage)

(use “git add/rm …” as appropriate to mark resolution)

both modified:

接下來,修改這些檔案。如果她對結果滿意了,和往常一樣緩存這些檔案,然後讓git rebase

完成接下來的工作:

git add

git rebase --continue

就是這樣。Git會繼續檢查下個送出,對沖突的送出重複這個流程。

如果你這時候發現不知道自己做了什麼,不要驚慌。隻要運作下面的指令,你就會回到開始之前的狀态:

git rebase --abort

Mary成功釋出了她的分支

在她和中央倉庫同步之後,Mary可以成功地釋出她的修改:

git push origin master

接下來該怎麼做

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

如果你的團隊已經習慣了中心化的工作流,但希望提高協作效率,那麼探索Feature分支工作流的好處是完全值當的。每個功能在專門的獨立分支上進行,在代碼并入官方項目之前就可以啟動圍繞新修改的深度讨論。

Feature分支的工作流

一旦你掌握了中心化工作流的使用姿勢,在你的開發流程中添加功能分支是一個簡單的方式,來促進協作和開發者之間的交流。這種封裝使得多個開發者專注自己的功能而不會打擾主代碼庫。它還保證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開始了一個新功能

在她開始開發一個功能之前,Mary需要一個獨立的分支。她可以用下面的指令建立新分支:

git checkout -b marys-feature master

一個基于master、名為marys-feature的分支将會被checkout,-b标記告訴Git在分支不存在時建立它。在這個分支上,Mary和往常一樣編輯、緩存、送出更改,用足夠多的送出來建構這個功能:

git statusgit add git commit

Mary去吃飯了

Mary在早上給她的功能添加了一些送出。在她去吃午飯前,将她的分支推送到中央倉庫是個不錯的想法。這是一種友善的備份,但如果Mary和其他開發者一起協作,他們也可以看到她的初始送出了。

git push -u origin marys-feature

這個指令将marys-feature推送到中央倉庫(origin),-u标記将它添加為遠端跟蹤的分支。在設定完跟蹤的分支之後,Mary調用不帶任何參數的git push來推送她的功能。

Mary完成了她的工作

當Mary吃完午飯回來,她完成了她的功能。在并入master之前,她需要釋出一個pull request,讓其他的團隊成員知道她所做的工作。但首先,她應該保證中央倉庫包含了她最新的送出:

git push

然後,她在她的Git界面上發起了一個pull request,請求将marys-feature合并進master,團隊成員會收到自動的通知。Pull request的好處是,評論顯示在相關的送出正下方,友善讨論特定的修改。

Bill收到了pull request

Bill收到了pull request,并且檢視了marys-feature。他決定在并入官方項目之前做一些小修改,通過pull request和Mary進行了溝通。

Mary作了修改

為了做這些更改,Mary重複了之前建立功能時相同的流程,她編輯、緩存、送出、将更新推送到中央倉庫。她所有的活動顯示在pull request中,Bill可以一直評論。

如果Bill想要的話,也可以将marys-featurepull到他自己的本地倉庫,繼續工作。後續的任何送出都會顯示在pull request上。

Mary釋出了她的功能

一旦Bill準備接受這個pull request,某個人(Bill或者Mary都可)需要将功能并入穩定的項目:

git checkout mastergit pullgit pull origin marys-featuregit 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工作流一節源于nvie網站上的作者Vincent Driessen。

Gitflow工作流圍繞項目釋出定義了一個嚴格的分支模型。有些地方比功能分支工作流更複雜,為管理大型項目提供了魯棒的架構。

和功能分支工作流相比,這種工作流沒有增加任何新的概念或指令。它給不同的分支指定了特定的角色,定義它們應該如何、什麼時候交流。除了功能分支之外,它還為準備釋出、維護釋出、記錄釋出分别使用了單獨的分支。當然,你還能享受到功能分支工作流帶來的所有好處:pull request、隔離實驗和更高效的協作。

如何工作

Gitflow工作流仍然使用中央倉庫作為開發者溝通的中心。和其他工作流一樣,開發者在本地工作,将分支推送到中央倉庫。唯一的差別在于項目的分支結構。

曆史分支

和單獨的master分支不同,這種工作流使用兩個分支來記錄項目曆史。master分支儲存官方釋出曆史,develop分支用來整合功能分支。同時,這還友善了在master分支上給所有送出打上版本号标簽。

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

功能分支

每個新功能都放置在自己的分支中,可以在備份/協作時推送到中央倉庫。但是,與其合并到master,功能分支将開發分支作為父分支。當一個功能完成時,它将被合并回develop。功能永遠不應該直接在master上互動。

注意,功能分支加上develop分支就是我們之前所說的功能分支工作流。但是,Gitflow工作流不止于此。

釋出分支

一旦develop分支的新功能足夠釋出(或者預先确定的釋出日期即将到來),你可以從develop分支fork一個釋出分支。這個分支的建立開始了下個釋出周期,隻有和釋出相關的任務應該在這個分支進行,如修複bug、生成文檔等。一旦準備好了釋出,釋出分支将合并進master,打上版本号的标簽。另外,它也應該合并回develop,後者可能在釋出啟動之後有了新的進展。

使用一個專門的分支來準備釋出確定一個團隊完善目前的釋出,其他團隊可以繼續開發下一個釋出的功能。它還建立了清晰的開發階段(比如說,“這周我們準備4.0版本的釋出”,而我們在倉庫的結構中也能看到這個階段)。

通常我們約定:

從develop建立分支

合并進master分支

命名規範release-* or release/*

維護分支

維護或者“緊急修複”分支用來快速給産品的釋出打上更新檔。這是唯一可以從master上fork的分支。一旦修複完成了,它應該被并入master和develop分支(或者目前的釋出分支),master應該打上更新的版本号的标簽。

有一個專門的bug修複開發線使得你的團隊能夠處理issues,而不打斷其他工作流或是要等到下一個釋出周期。你可以将維護分支看作在master分支上工作的臨時釋出分支。

栗子

下面的栗子示範了這種工作流如何用來管理釋出周期。假設你已經建立了中央倉庫。

建立一個開發分支

你要做的第一步是為預設的master分支建立一個互補的develop分支。最簡單的辦法是在本地建立一個空的develop分支,将它推送到伺服器上:

git branch developgit push -u origin develop

這個分支将會包含項目中所有的曆史,而master将包含不完全的版本。其他開發者應該将中央倉庫克隆到本地,建立一個分支來追蹤develop分支:

git clone ssh://[email protected]/path/to/repo.gitgit checkout -b develop origin/develop

現在所有人都有了一份曆史分支的本地副本。

Mary和John開始了新功能

我們的栗子從John和Mary在不同分支上工作開始。他們都要為自己的功能建立單獨的分支。他們的功能分支都應該基于develop,而不是master:

git checkout -b some-feature develop

他們都使用“編輯、緩存、送出”的一般約定來向功能分支添加送出:

git statusgit add git commit

Mary完成了她的功能

在添加了一些送出之後,Mary确信她的功能以及準備好了。如果她的團隊使用pull request,現在正是發起pull request的好時候,請求将她的功能并入develop分支。否則,她可以向下面一樣,将它并入本地的develop分支,推送到中央倉庫:

git pull origin developgit checkout developgit merge some-featuregit pushgit branch -d some-feature

第一個指令在嘗試并入功能分支之前確定develop分支已是最新。注意,功能絕不該被直接并入master。沖突的處理方式和中心化工作流相同。

Mary開始準備釋出

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

git checkout -b release-0.1 develop

這個分支用來整理送出,充分測試,更新文檔,為即将到來的釋出做各種準備。它就像是一個專門用來完善釋出的功能分支。

一旦Mary建立了這個分支,推送到中央倉庫,這次釋出的功能便被鎖定了。不在develop分支中的功能将被推遲到下個釋出周期。

Mary完成了她的釋出

一旦釋出準備穩妥,Mary将它并入master和develop,然後删除釋出分支。合并回develop很重要,因為可能已經有關鍵的更新添加到了釋出分支上,而開發新功能需要用到它們。同樣的,如果Mary的團隊重視代碼審查,現在将是發起pull request的完美時機。

git checkout mastergit merge release-0.1git pushgit checkout developgit merge release-0.1git pushgit branch -d release-0.1

釋出分支是功能開發(develop)和公開釋出(master)之間的過渡階段。不論什麼時候将送出并入master時,你應該為送出打上友善引用的标簽:

git tag -a 0.1 -m “Initial public release” mastergit push --tags

Git提供了許多鈎子,即倉庫中特定事件發生時被執行的腳本。當你向中央倉庫推送master分支或者标簽時,你可以配置一個鈎子來自動化建構公開釋出。

終端使用者發現了一個bug

正式釋出之後,Mary回過頭來和John一起為下一個釋出開發功能。這時,一個終端使用者開了一個issue抱怨說目前釋出中存在一個bug。為了解決這個bug,Mary(或John)從master建立了一個維護分支,用幾個送出修複這個issue,然後直接合并回master。

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

和釋出分支一樣,維護分支包含了develop中需要的重要更新,是以Mary同樣需要執行這個合并。接下來,她可以删除這個分支了:

git checkout developgit merge issue-#001git pushgit branch -d issue-#001

接下來該怎麼做

現在,希望你已經很熟悉中心化的工作流、功能分支工作流和Gitflow工作流。你應該已經可以抓住本地倉庫、推送/拉取模式,和Git魯棒的分支和合并模型的無限潛力。

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

Fork工作流

Fork工作流和教程中讨論的其它工作流截然不同。與其使用唯一的服務端倉庫作為”中央“代碼庫,它給予 每個 開發者一個服務端倉庫。也就是說每個貢獻者都有兩個Git倉庫,而不是一個:一個私有的本地倉庫和一個公開的服務端倉庫。

Fork工作流的主要優點在于貢獻可以輕易地整合進項目,而不需要每個人都推送到單一的中央倉庫。開發者推送到他們 自己的 服務端倉庫,隻有項目管理者可以推送到官方倉庫。這使得管理者可以接受任何開發者的送出,卻不需要給他們中央倉庫的權限。

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

如何工作

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

取而代之地,他們fork一份官方項目,在服務端建立一份副本。這份建立的副本作為他們私有的公開倉庫——沒有其他開發者可以在上面推送,但他們可以從上面拉取修改(在後面我們會讨論為什麼這一點很重要)。在他們建立了服務端副本之後,開發者執行git clone操作,在他們的本地機器上複制一份。這是他們私有的開發環境,正如其他工作流中一樣。

當他們準備好釋出本地送出時,他們将送出推送到自己的公開倉庫——而非官方倉庫。然後,他們向主倉庫發起一個pull request,讓項目維護者知道一個更新做好了合并的準備。如果貢獻的代碼有什麼問題的話,Pull request可以作為一個友善的讨論版。

我為了将功能并入官方代碼庫,維護者将貢獻者的修改拉取到他們的本地倉庫,確定修改不會破壞項目,将它合并到本地的master分支,然後将master分支推送到服務端的官方倉庫。貢獻現在已是項目的一部分,其他開發者應該從官方倉庫拉取并同步他們的本地倉庫。

中央倉庫

“官方”倉庫這個概念在Fork工作流中隻是一個約定,了解這一點很重要。從技術的角度,Git并看不出每個開發者和官方的公開倉庫有什麼差別。事實上,官方倉庫唯一官方的原因是,它是項目維護者的倉庫。

Fork工作流中的分支

所有這些個人的公開倉庫隻是一個在開發者之間共享分支的約定。每個人仍然可以使用分支來隔離功能,就像在功能分支工作流和Gitflow工作流中一樣。唯一的差別在于這些分支是如何開始的。在Fork工作流中,它們從另一個開發者的本地倉庫拉取而來,而在功能分支和Gitflow分支它們被推送到官方倉庫。

栗子

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

和任何基于Git的項目一樣,第一步是在服務端建立一個可以被所有項目成員通路到的官方倉庫。一般來說,這個倉庫同時還是項目維護者的公開倉庫。

公開的倉庫應該永遠是裸的,不管它們是否代表官方代碼庫。是以項目維護者應該運作下面這樣的指令來設定官方倉庫:

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

Github同時提供了一個圖形化界面來替代上面的操作。這和教程中其它工作流設定中央倉庫的流程完全一緻。如果有必要的話,項目維護者應該将已有的代碼庫推送到這個倉庫中。

開發者fork倉庫

接下來,所有開發者需要fork官方倉庫。你可以用SSH到伺服器,運作git clone将它複制到伺服器的另一個位址——fork其實隻是服務端的clone。但同樣地,Github上開發者隻需點一點按鈕就可以fork倉庫。

在這步之後,每個開發者應該都有了自己的服務端倉庫。像官方倉庫一樣,所有這些倉庫都應該是裸倉庫。

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

接下來開發者需要克隆他們自己的公開倉庫。他們可以用熟悉的git clone指令來完成這一步。

我們的栗子假設使用他們使用Github來托管倉庫。記住,在這種情況下,每個開發者應該有他們自己的Github賬号,應該用下面的指令克隆服務端倉庫:

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

而教程中的其他工作流使用單一的origin遠端連接配接,指向中央倉庫,Fork工作流需要兩個遠端連接配接,一個是中央倉庫,另一個是開發者個人的服務端倉庫。你可以給這些遠端取任何名字,約定的做法是将origin作為你fork後的倉庫的遠端(運作git clone是會自動建立)和upstream作為官方項目。

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

你需要使用上面的指令來建立上遊倉庫的遠端連接配接。它使得你輕易地保持本地倉庫和官方倉庫的進展同步。注意如果你的上遊倉庫開啟了認證(比如它沒有開源),你需要提供一個使用者名,就像這樣:

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

它需要使用者從官方代碼庫克隆或拉取之前提供有效的密碼。

開發者進行自己的開發

在他們剛克隆的本地倉庫中,開發者可以編輯代碼、送出更改,和其它分支中一樣######建立分支:

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

他們所有的更改在推送到公開倉庫之前都是完全私有的。而且,如果官方項目已經向前進展了,他們可以用git pull擷取新的送出:

git pull upstream master

因為開發者應該在專門的功能分支開發,這一般會産生一個快速向前的合并。

開發者釋出他們的功能

一旦開發者準備好共享他們的新功能,他們需要做兩件事情。第一,他們必須将貢獻的代碼推送到自己的公開倉庫,讓其他開發者能夠通路到。他們的origin遠端應該已經設定好了,是以他們隻需要:

git push origin feature-branch

這和其他工作流不同之處在于,origin遠端指向開發者個人的服務端倉庫,而不是主代碼庫。

第二,他們需要通知項目維護者,他們想要将功能并入官方代碼庫。Github提供了一個“New Pull Request”按鈕,跳轉到一個網頁,讓你指明想要并入主倉庫的分支。一般來說,你希望将功能分支并入上遊遠端的master分支。

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

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

直接檢查pull request中檢查代碼

将代碼拉取到本地倉庫然後手動合并

第一個選項更簡單,讓維護者檢視修改前後的差異,在上面評論,然後通過圖形界面執行合并。然而,如果pull request會導緻合并沖突,第二個選項就有了必要。在這個情況中,維護者需要從開發者的服務端倉庫fetch功能分支,合并到他們本地的master分支,然後解決沖突:

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

一旦修改被整合進本地的master,維護者需要将它推送到伺服器上的官方倉庫,這樣其他開發者也可以通路它:

git push origin master

記住,維護者的origin指向他們的公開倉庫,也就是項目的官方代碼庫。開發者的貢獻現在完全并入了項目。

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

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

git pull upstream master

接下來該怎麼做

如果你從SVN遷移而來,Fork工作流看上去是一個比較大的轉變。但不要害怕——它隻是在Feature分支工作流之上引入了一層抽象。貢獻的代碼釋出到開發者在服務端自己的倉庫,而不是在唯一的中央倉庫中直接共享分支。

這篇文章解釋了一次代碼貢獻是如何從一個開發者流入官方的master分支的,但相同的方法可以用在将代碼貢獻整合進任何倉庫。比如,如果你團隊的一部分成員在一個特定功能上協作,他們可以用自己約定的行為共享修改——而不改變主倉庫。

這使得Fork工作流對于松散的團隊來說是個非常強大的工具。任何開發者都可以輕而易舉地和其他開發者共享修改,任何分支都能高效地并入主代碼庫。

8人點贊

随筆

作者:Ketine

連結:https://www.jianshu.com/p/0d8ff3324535

來源:簡書

著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。