四中常用的Git工作流比較

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

閱讀的時候旨怠,請記住工作流應該是一種規(guī)范而不是金科玉律渠驼。我們希望向你展示所有工作流,讓你融會貫通鉴腻,因地制宜迷扇。

這份教程討論了下面四種工作流:
1.中心化的工作流
2.基于功能分支的工作流
3.Gitflow工作流
4.Fork工作流

中心化的工作流

過渡到分布式分版本控制系統(tǒng)看起來是個令人恐懼的任務,但你不必為了利用Git的優(yōu)點而改變你現(xiàn)有的工作流爽哎。你的團隊仍然可以用以前SVN的方式開發(fā)項目蜓席。
然而,使用Git來驅動你的開發(fā)工作流顯示出了一些SVN沒有的優(yōu)點课锌。首先厨内,它讓每個開發(fā)者都有了自己 本地 的完整項目副本。隔離的環(huán)境使得每個開發(fā)者的工作獨立于項目的其它修改——他們可以在自己的本地倉庫中添加提交渺贤,完全無視上游的開發(fā)雏胃,直到需要的時候。
第二志鞍,它讓你接觸到了Git魯棒的分支和合并模型瞭亮。和SVN不同,Git分支被設計為一種故障安全的機制述雾,用來在倉庫之間整合代碼和共享更改街州。

如何工作

和Subversion一樣,中心化的工作流將中央倉庫作為項目中所有修改的唯一入口玻孟。和trunk
不同唆缴,默認的開發(fā)分支叫做master,所有更改都被提交到這個分支黍翎。這種工作流不需要master之外的其它分支面徽。
開發(fā)者將中央倉庫克隆到本地后開始工作。在他們的本地項目副本中匣掸,他們可以像SVN一樣修改文件和提交更改趟紊;不過,這些新的提交被保存在 本地 ——它們和中央倉庫完全隔離碰酝。這使得開發(fā)者可以將和上游的同步推遲到他們方便的時候霎匈。
為了向官方項目發(fā)布修改,開發(fā)者將他們的本地master分支“推送”到中央倉庫送爸。這一步等同于svn commit铛嘱,除了Git添加的是所有不在中央master分支上的本地提交暖释。

管理沖突

中央倉庫代表官方項目,因此它的提交歷史應該被視作神圣不可更改的墨吓。如果開發(fā)者的本地提交和中央倉庫分叉了球匕,Git會拒絕將他們的修改推送上去,因為這會覆蓋官方提交帖烘。
在開發(fā)者發(fā)布他們的功能之前亮曹,他們需要fetch更新的中央提交,在它們之上rebase自己的更改秘症。這就像是:“我想要在其他人的工作進展之上添加我的修改照卦。”它會產(chǎn)生完美的線性歷史乡摹,就像和傳統(tǒng)的SVN工作流一樣窄瘟。
如果本地修改和上游提交沖突時,Git會暫停rebase流程趟卸,給你機會手動解決這些沖突。Git很贊的一點是氏义,它將git status
git add
命令同時用來生成提交和解決合并沖突锄列。這使得開發(fā)者能夠輕而易舉地管理他們的合并。另外惯悠,如果他們改錯了什么邻邮,Git讓他們輕易地退出rebase過程,然后重試(或者找人幫忙)克婶。

栗子

讓我們一步步觀察一個普通的小團隊是如何使用這種工作流協(xié)作的筒严。我們有兩位開發(fā)者,John和Mary情萤,分別在開發(fā)兩個功能鸭蛙,他們通過中心化的倉庫共享代碼。

一人初始化了中央倉庫

首先筋岛,需要有人在服務器上創(chuàng)建中央倉庫娶视。如果這是一個新項目,你可以初始化一個空的倉庫睁宰。不然肪获,你需要導入一個已經(jīng)存在的Git或SVN項目。
中央倉庫應該永遠是裸倉庫(沒有工作目錄)柒傻,可以這樣創(chuàng)建:
ssh user@host git init --bare /path/to/repo.git
但確保你使用的SSH用戶名user孝赫、服務器host的域名或IP地址、儲存?zhèn)}庫的地址/path/to/repo.git是有效的红符。注意.git約定俗成地出現(xiàn)在倉庫名的后面青柄,表明這是一個裸倉庫伐债。

所有人將倉庫克隆到本地

接下來,每個開發(fā)者在本地創(chuàng)建一份完整項目的副本刹前。使用git clone
命令:
git clone ssh://user@host/path/to/repo.git

John在開發(fā)他的功能

在他的本地倉庫中泳赋,John可以用標準的Git提交流程開發(fā)功能:編輯、緩存喇喉、提交祖今。如果你對緩存區(qū)還不熟悉,你也可以不用記錄工作目錄中每次的變化拣技。于是你創(chuàng)建了一個高度集中的提交千诬,即使你已經(jīng)在本地做了很多修改。
git status # 查看倉庫狀態(tài)
git add <some-file> # 緩存一個文件
git commit # 提交一個文件</some-file>
記住膏斤,這些命令創(chuàng)建的是本地提交徐绑,John可以周而復始地重復這個過程,而不用考慮中央倉庫莫辨。對于龐大的功能傲茄,需要切成更簡單、原子化的片段時沮榜,這個特性就很有用盘榨。

Mary在開發(fā)她的功能

同時,Mary在她自己的本地倉庫用相同的編輯/緩存/提交流程開發(fā)她的功能蟆融。和John一樣草巡,她不需要關心中央倉庫的進展,她也 完全 不關心John在他自己倉庫中做的事型酥,因為所有本地倉庫都是私有的山憨。

John發(fā)布了他的功能

一旦John完成了他的功能,他應該將本地提交發(fā)布到中央倉庫弥喉,這樣其他項目成員就可以訪問了郁竟。他可以使用git push命令,就像:
git push origin master
記住档桃,origin是John克隆中央倉庫時指向它的遠程連接枪孩。master參數(shù)告訴Git試著將origin的master分支變得和他本地的master分支一樣。中央倉庫在John克隆之后還沒有進展藻肄,因此這個推送如他所愿蔑舞,沒有產(chǎn)生沖突。

Mary試圖發(fā)布她的功能

John已經(jīng)成功地將他的更改發(fā)布到了中央倉庫上嘹屯,看看當Mary試著將她的功能推送到上面時會發(fā)生什么攻询。她可以使用同一個推送命令:
John已經(jīng)成功地將他的更改發(fā)布到了中央倉庫上,看看當Mary試著將她的功能推送到上面時會發(fā)生什么州弟。她可以使用同一個推送命令:
git push origin master
但是钧栖,她的本地歷史和中央倉庫已經(jīng)分叉了低零,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分支庆械。也就是說垦页,你可以一個個提交分別解決合并沖突,而不是在一個龐大的合并提交中解決干奢。它會讓你的每個提交保持專注,并獲得一個干凈的項目歷史盏袄。另一方面忿峻,你更容易發(fā)現(xiàn)bug是在哪引入的,如果有必要的話辕羽,用最小的代價回滾這些修改逛尚。
如果Mary和John開發(fā)的功能沒有關聯(lián),rebase的過程不太可能出現(xiàn)沖突刁愿。但如果出現(xiàn)沖突時绰寞,Git在當前提交會暫停rebase,輸出下面的信息铣口,和一些相關的指令:
CONFLICT (content): Merge conflict in <some-file>
Git的優(yōu)點在于 每個人 都能解決他們自己的合并沖突滤钱。在這個例子中,Mary只需運行一下git status
就可以發(fā)現(xiàn)問題是什么脑题。沖突的文件會出現(xiàn)在未合并路徑中:
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會繼續(xù)檢查下個提交,對沖突的提交重復這個流程痊末。
如果你這時候發(fā)現(xiàn)不知道自己做了什么蚕苇,不要驚慌。只要運行下面的命令凿叠,你就會回到開始之前的狀態(tài):
git rebase --abort

Mary成功發(fā)布了她的分支

在她和中央倉庫同步之后涩笤,Mary可以成功地發(fā)布她的修改:
git push origin master

接下來該怎么做

正如你所見,使用一丟丟Git命令來復制一套傳統(tǒng)的Subversion開發(fā)環(huán)境也是可行的幔嫂。這對于從SVN轉變而來的團隊來說很棒辆它,但這樣沒有利用到Git分布式的本質。
如果你的團隊已經(jīng)習慣了中心化的工作流履恩,但希望提高協(xié)作效率锰茉,那么探索Feature分支工作流的好處是完全值當?shù)摹C總€功能在專門的獨立分支上進行切心,在代碼并入官方項目之前就可以啟動圍繞新修改的深度討論飒筑。

Feature分支的工作流

一旦你掌握了中心化工作流的使用姿勢,在你的開發(fā)流程中添加功能分支是一個簡單的方式绽昏,來促進協(xié)作和開發(fā)者之間的交流协屡。這種封裝使得多個開發(fā)者專注自己的功能而不會打擾主代碼庫。它還保證master分支永遠不會包含損壞的代碼全谤,給持續(xù)集成環(huán)境帶來了是很大的好處肤晓。

封裝功能的開發(fā)使得pull request的使用成為可能,用來啟動圍繞一個分支的討論认然。它給了其他開發(fā)者在功能并入主項目之前參與決策的機會补憾。或者卷员,如果你開發(fā)功能時卡在一半盈匾,你可以發(fā)起一個pull request,向同事尋求建議毕骡。重點是削饵,pull request使得你的團隊在評論其他人的工作時變得非常簡單。

如何工作

Feature分支工作流同樣使用中央倉庫未巫,master同樣代表官方的項目歷史窿撬。但是,與其直接提交在本地的master分支叙凡,開發(fā)者每次進行新的工作時創(chuàng)建一個新的分支尤仍。Feature分支應該包含描述性的名稱,比如animated-menu-items(菜單項動畫)或issue-#1061狭姨。每個分支都應該有一個清晰宰啦、高度集中的目的苏遥。

Git在技術上無法區(qū)別master和功能分支,所以開發(fā)者可以在feature分支上編輯赡模、緩存田炭、提交胎食,就和中心化工作流中一樣策泣。

此外灵汪,feature分支可以(也應該)被推送到中央倉庫咖城。這使得你和其他開發(fā)者共享這個功能,而又不改變官方代碼檬贰。既然master只是一個“特殊”的分支徒欣,在中央倉庫中儲存多個feature分支不會引出什么問題炼杖。當然了锋玲,這也是備份每個開發(fā)者本地提交的好辦法景用。

Pull Request

除了隔離功能開發(fā)之外,分支使得通過pull request討論修改成為可能惭蹂。一旦有人完成了一個功能伞插,他們不會立即將它并入master。他們將feature分支推送到中央服務器上盾碗,發(fā)布一個pull request媚污,請求將他們的修改并入master。這給了其他開發(fā)者在修改并入主代碼庫之前審查的機會廷雅。

代碼審查是pull request的主要好處耗美,但他們事實上被設計為成為討論代碼的一般場所。你可以把pull request看作是專注某個分支的討論版航缀。也就是說他們可以用于開發(fā)流程之前幽歼。比如,一個開發(fā)者在某個功能上需要幫助谬盐,他只需發(fā)起一個pull request。感興趣的小伙伴會自動收到通知诚些,看到相關提交中的問題飞傀。

一旦pull request被接受了,發(fā)布功能的行為和中心化的工作流是一樣的诬烹。首先砸烦,確定你本地的master和上游的master已經(jīng)同步。然后绞吁,將feature分支并入master幢痘,將更新的master推送回中央倉庫。

栗子

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

Mary開始了一個新功能

在她開始開發(fā)一個功能之前购岗,Mary需要一個獨立的分支。她可以用下面的命令創(chuàng)建新分支:
git checkout -b marys-feature master

一個基于master门粪、名為marys-feature的分支將會被checkout喊积,-b標記告訴Git在分支不存在時創(chuàng)建它。在這個分支上玄妈,Mary和往常一樣編輯乾吻、緩存、提交更改拟蜻,用足夠多的提交來構建這個功能:
git statusgit add <some-file>git commit

Mary去吃飯了

Mary在早上給她的功能添加了一些提交绎签。在她去吃午飯前,將她的分支推送到中央倉庫是個不錯的想法酝锅。這是一種方便的備份诡必,但如果Mary和其他開發(fā)者一起協(xié)作,他們也可以看到她的初始提交了屈张。
git push -u origin marys-feature

這個命令將marys-feature推送到中央倉庫(origin)擒权,-u標記將它添加為遠程跟蹤的分支。在設置完跟蹤的分支之后阁谆,Mary調用不帶任何參數(shù)的git push來推送她的功能碳抄。

Mary完成了她的工作

當Mary吃完午飯回來,她完成了她的功能场绿。在并入master之前剖效,她需要發(fā)布一個pull request,讓其他的團隊成員知道她所做的工作焰盗。但首先璧尸,她應該保證中央倉庫包含了她最新的提交:
git push

然后,她在她的Git界面上發(fā)起了一個pull request熬拒,請求將marys-feature合并進master爷光,團隊成員會收到自動的通知。Pull request的好處是澎粟,評論顯示在相關的提交正下方蛀序,方便討論特定的修改。

Bill收到了pull request

Bill收到了pull request活烙,并且查看了marys-feature徐裸。他決定在并入官方項目之前做一些小修改,通過pull request和Mary進行了溝通啸盏。

Mary作了修改

為了做這些更改重贺,Mary重復了之前創(chuàng)建功能時相同的流程,她編輯、緩存气笙、提交次企、將更新推送到中央倉庫。她所有的活動顯示在pull request中健民,Bill可以一直評論抒巢。

如果Bill想要的話,也可以將marys-featurepull到他自己的本地倉庫秉犹,繼續(xù)工作蛉谜。后續(xù)的任何提交都會顯示在pull request上。

Mary發(fā)布了她的功能

一旦Bill準備接受這個pull request崇堵,某個人(Bill或者Mary都可)需要將功能并入穩(wěn)定的項目:
git checkout mastergit pullgit pull origin marys-featuregit push

首先型诚,不管是誰在執(zhí)行合并,都要保證他們的master分支是最新的鸳劳。然后狰贯,運行git pull origin marys-feature合并中央倉庫的marys-feature副本。你也可以使用簡單的git merge marys-feature赏廓,但之前的命令保證你拉取下來的一定是功能分支最新的版本涵紊。最后,更新的master需要被推送回origin幔摸。

這個過程導致了一個合并提交摸柄。一些開發(fā)者喜歡它,因為它是功能和其余代碼合并的標志既忆。但驱负,如果你希望得到線性的歷史,你可以在執(zhí)行merge之前將功能rebase到master分支的頂端患雇,產(chǎn)生一個快速向前的合并跃脊。

一些界面會自動化接受pull request的流程,只需點擊一下“Merge Pull Request”苛吱。如果你的沒有的話酪术,它至少在合并之后應該可以自動地關閉pull request。
同時翠储,John以同樣的方式工作著

Mary和Bill一起開發(fā)marys-feature绘雁,在pull request上討論的同時,John還在開發(fā)他自己的feature分支彰亥。通過將功能用不同分支隔離開來,每個人可以獨立地工作衰齐,但很容易和其他開發(fā)者共享修改任斋。

接下來該怎么做

為了徹底了解Github上的功能分支,你應該查看使用分支一章。現(xiàn)在废酷,你應該已經(jīng)看到了功能分支極大地增強了中心化工作流中單一master分支的作用瘟檩。除此之外,功能分支還便利了pull request的使用澈蟆,在版本控制界面上直接討論特定的提交墨辛。Gitflow工作流是管理功能開發(fā)、發(fā)布準備趴俘、維護的常見模式睹簇。

Gitflow工作流

下面的Gitflow工作流一節(jié)源于nvie網(wǎng)站上的作者Vincent Driessen。

Gitflow工作流圍繞項目發(fā)布定義了一個嚴格的分支模型寥闪。有些地方比功能分支工作流更復雜太惠,為管理大型項目提供了魯棒的框架。

和功能分支工作流相比疲憋,這種工作流沒有增加任何新的概念或命令凿渊。它給不同的分支指定了特定的角色,定義它們應該如何缚柳、什么時候交流埃脏。除了功能分支之外,它還為準備發(fā)布秋忙、維護發(fā)布彩掐、記錄發(fā)布分別使用了單獨的分支。當然翰绊,你還能享受到功能分支工作流帶來的所有好處:pull request佩谷、隔離實驗和更高效的協(xié)作。

如何工作

Gitflow工作流仍然使用中央倉庫作為開發(fā)者溝通的中心监嗜。和其他工作流一樣谐檀,開發(fā)者在本地工作,將分支推送到中央倉庫裁奇。唯一的區(qū)別在于項目的分支結構桐猬。

歷史分支

和單獨的master分支不同,這種工作流使用兩個分支來記錄項目歷史刽肠。master分支儲存官方發(fā)布歷史溃肪,develop分支用來整合功能分支。同時音五,這還方便了在master分支上給所有提交打上版本號標簽惫撰。

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

功能分支

每個新功能都放置在自己的分支中躺涝,可以在備份/協(xié)作時推送到中央倉庫厨钻。但是,與其合并到master,功能分支將開發(fā)分支作為父分支夯膀。當一個功能完成時诗充,它將被合并回develop。功能永遠不應該直接在master上交互诱建。

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

發(fā)布分支

一旦develop分支的新功能足夠發(fā)布(或者預先確定的發(fā)布日期即將到來),你可以從develop分支fork一個發(fā)布分支辜荠。這個分支的創(chuàng)建開始了下個發(fā)布周期汽抚,只有和發(fā)布相關的任務應該在這個分支進行,如修復bug伯病、生成文檔等造烁。一旦準備好了發(fā)布,發(fā)布分支將合并進master午笛,打上版本號的標簽惭蟋。另外,它也應該合并回develop药磺,后者可能在發(fā)布啟動之后有了新的進展告组。

使用一個專門的分支來準備發(fā)布確保一個團隊完善當前的發(fā)布,其他團隊可以繼續(xù)開發(fā)下一個發(fā)布的功能癌佩。它還建立了清晰的開發(fā)階段(比如說木缝,“這周我們準備4.0版本的發(fā)布”,而我們在倉庫的結構中也能看到這個階段)围辙。

通常我們約定:
從develop創(chuàng)建分支

合并進master分支

命名規(guī)范release-* or release/*

維護分支

維護或者“緊急修復”分支用來快速給產(chǎn)品的發(fā)布打上補丁我碟。這是唯一可以從master上fork的分支。一旦修復完成了姚建,它應該被并入master和develop分支(或者當前的發(fā)布分支)矫俺,master應該打上更新的版本號的標簽。

有一個專門的bug修復開發(fā)線使得你的團隊能夠處理issues掸冤,而不打斷其他工作流或是要等到下一個發(fā)布周期厘托。你可以將維護分支看作在master分支上工作的臨時發(fā)布分支。

栗子

下面的栗子演示了這種工作流如何用來管理發(fā)布周期稿湿。假設你已經(jīng)創(chuàng)建了中央倉庫铅匹。

創(chuàng)建一個開發(fā)分支

你要做的第一步是為默認的master分支創(chuàng)建一個互補的develop分支。最簡單的辦法是在本地創(chuàng)建一個空的develop分支饺藤,將它推送到服務器上:
git branch developgit push -u origin develop

這個分支將會包含項目中所有的歷史包斑,而master將包含不完全的版本考杉。其他開發(fā)者應該將中央倉庫克隆到本地,創(chuàng)建一個分支來追蹤develop分支:
git clone ssh://user@host/path/to/repo.gitgit checkout -b develop origin/develop

現(xiàn)在所有人都有了一份歷史分支的本地副本舰始。

Mary和John開始了新功能

我們的栗子從John和Mary在不同分支上工作開始。他們都要為自己的功能創(chuàng)建單獨的分支咽袜。他們的功能分支都應該基于develop丸卷,而不是master:
git checkout -b some-feature develop

他們都使用“編輯、緩存询刹、提交”的一般約定來向功能分支添加提交:
git statusgit add <some-file>git commit

Mary完成了她的功能

在添加了一些提交之后谜嫉,Mary確信她的功能以及準備好了。如果她的團隊使用pull request凹联,現(xiàn)在正是發(fā)起pull request的好時候沐兰,請求將她的功能并入develop分支。否則蔽挠,她可以向下面一樣住闯,將它并入本地的develop分支,推送到中央倉庫:
git pull origin developgit checkout developgit merge some-featuregit pushgit branch -d some-feature

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

Mary開始準備發(fā)布

當John仍然在他的功能分支上工作時量窘,Mary開始準備項目的第一個官方發(fā)布。和開發(fā)功能一樣氢拥,她新建了一個分支來封裝發(fā)布的準備工作蚌铜。這也正是發(fā)布的版本號創(chuàng)建的一步:
git checkout -b release-0.1 develop

這個分支用來整理提交,充分測試嫩海,更新文檔冬殃,為即將到來的發(fā)布做各種準備。它就像是一個專門用來完善發(fā)布的功能分支出革。

一旦Mary創(chuàng)建了這個分支造壮,推送到中央倉庫,這次發(fā)布的功能便被鎖定了骂束。不在develop分支中的功能將被推遲到下個發(fā)布周期耳璧。

Mary完成了她的發(fā)布

一旦發(fā)布準備穩(wěn)妥,Mary將它并入master和develop展箱,然后刪除發(fā)布分支旨枯。合并回develop很重要,因為可能已經(jīng)有關鍵的更新添加到了發(fā)布分支上混驰,而開發(fā)新功能需要用到它們攀隔。同樣的皂贩,如果Mary的團隊重視代碼審查,現(xiàn)在將是發(fā)起pull request的完美時機昆汹。
git checkout mastergit merge release-0.1git pushgit checkout developgit merge release-0.1git pushgit branch -d release-0.1

發(fā)布分支是功能開發(fā)(develop)和公開發(fā)布(master)之間的過渡階段明刷。不論什么時候將提交并入master時,你應該為提交打上方便引用的標簽:
git tag -a 0.1 -m "Initial public release" mastergit push --tags

Git提供了許多鉤子满粗,即倉庫中特定事件發(fā)生時被執(zhí)行的腳本辈末。當你向中央倉庫推送master分支或者標簽時,你可以配置一個鉤子來自動化構建公開發(fā)布映皆。

終端用戶發(fā)現(xiàn)了一個bug

正式發(fā)布之后挤聘,Mary回過頭來和John一起為下一個發(fā)布開發(fā)功能。這時捅彻,一個終端用戶開了一個issue抱怨說當前發(fā)布中存在一個bug组去。為了解決這個bug,Mary(或John)從master創(chuàng)建了一個維護分支步淹,用幾個提交修復這個issue从隆,然后直接合并回master。
git checkout -b issue-#001 master# Fix the buggit checkout mastergit merge issue-#001git push

和發(fā)布分支一樣缭裆,維護分支包含了develop中需要的重要更新广料,因此Mary同樣需要執(zhí)行這個合并。接下來幼驶,她可以刪除這個分支了:
git checkout developgit merge issue-#001git pushgit branch -d issue-#001

接下來該怎么做

現(xiàn)在艾杏,希望你已經(jīng)很熟悉中心化的工作流、功能分支工作流和Gitflow工作流盅藻。你應該已經(jīng)可以抓住本地倉庫购桑、推送/拉取模式,和Git魯棒的分支和合并模型的無限潛力氏淑。

請記住勃蜘,教程中呈現(xiàn)的工作流只是可行的實踐——而非工作中使用Git的金科玉律。因此假残,盡情地取其精華缭贡,去其糟粕吧。不變的是要讓Git為你所用辉懒,而不是相反阳惹。

Fork工作流

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

Fork工作流的主要優(yōu)點在于貢獻可以輕易地整合進項目纲岭,而不需要每個人都推送到單一的中央倉庫抹竹。開發(fā)者推送到他們 自己的 服務端倉庫,只有項目管理者可以推送到官方倉庫止潮。這使得管理者可以接受任何開發(fā)者的提交窃判,卻不需要給他們中央倉庫的權限。

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

如何工作

和其它Git工作流一樣,F(xiàn)ork工作流以一個儲存在服務端的官方公開項目開場雳殊。但新的開發(fā)者想?yún)⑴c項目時橘沥,他們不直接克隆官方項目。

取而代之地夯秃,他們fork一份官方項目座咆,在服務端創(chuàng)建一份副本。這份新建的副本作為他們私有的公開倉庫——沒有其他開發(fā)者可以在上面推送仓洼,但他們可以從上面拉取修改(在后面我們會討論為什么這一點很重要)介陶。在他們創(chuàng)建了服務端副本之后,開發(fā)者執(zhí)行git clone操作色建,在他們的本地機器上復制一份哺呜。這是他們私有的開發(fā)環(huán)境,正如其他工作流中一樣箕戳。

當他們準備好發(fā)布本地提交時某残,他們將提交推送到自己的公開倉庫——而非官方倉庫。然后陵吸,他們向主倉庫發(fā)起一個pull request玻墅,讓項目維護者知道一個更新做好了合并的準備。如果貢獻的代碼有什么問題的話壮虫,Pull request可以作為一個方便的討論版澳厢。

我為了將功能并入官方代碼庫,維護者將貢獻者的修改拉取到他們的本地倉庫囚似,確保修改不會破壞項目剩拢,將它合并到本地的master分支,然后將master分支推送到服務端的官方倉庫饶唤。貢獻現(xiàn)在已是項目的一部分裸扶,其他開發(fā)者應該從官方倉庫拉取并同步他們的本地倉庫。

中央倉庫

“官方”倉庫這個概念在Fork工作流中只是一個約定搬素,理解這一點很重要呵晨。從技術的角度魏保,Git并看不出每個開發(fā)者和官方的公開倉庫有什么區(qū)別。事實上摸屠,官方倉庫唯一官方的原因是谓罗,它是項目維護者的倉庫。

Fork工作流中的分支

所有這些個人的公開倉庫只是一個在開發(fā)者之間共享分支的約定季二。每個人仍然可以使用分支來隔離功能檩咱,就像在功能分支工作流和Gitflow工作流中一樣。唯一的區(qū)別在于這些分支是如何開始的胯舷。在Fork工作流中刻蚯,它們從另一個開發(fā)者的本地倉庫拉取而來,而在功能分支和Gitflow分支它們被推送到官方倉庫桑嘶。

栗子

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

和任何基于Git的項目一樣炊汹,第一步是在服務端創(chuàng)建一個可以被所有項目成員訪問到的官方倉庫。一般來說逃顶,這個倉庫同時還是項目維護者的公開倉庫讨便。

公開的倉庫應該永遠是裸的,不管它們是否代表官方代碼庫以政。所以項目維護者應該運行下面這樣的命令來設置官方倉庫:
ssh user@hostgit init --bare /path/to/repo.git

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

開發(fā)者fork倉庫

接下來,所有開發(fā)者需要fork官方倉庫抖誉。你可以用SSH到服務器昙啄,運行git clone將它復制到服務器的另一個地址——fork其實只是服務端的clone。但同樣地寸五,Github上開發(fā)者只需點一點按鈕就可以fork倉庫梳凛。

在這步之后,每個開發(fā)者應該都有了自己的服務端倉庫梳杏。像官方倉庫一樣韧拒,所有這些倉庫都應該是裸倉庫。

開發(fā)者將fork的倉庫克隆到本地

接下來開發(fā)者需要克隆他們自己的公開倉庫十性。他們可以用熟悉的git clone命令來完成這一步叛溢。

我們的栗子假設使用他們使用Github來托管倉庫。記住劲适,在這種情況下楷掉,每個開發(fā)者應該有他們自己的Github賬號,應該用下面的命令克隆服務端倉庫:
git clone https://user@github.com/user/repo.git

而教程中的其他工作流使用單一的origin遠程連接霞势,指向中央倉庫烹植,F(xiàn)ork工作流需要兩個遠程連接斑鸦,一個是中央倉庫,另一個是開發(fā)者個人的服務端倉庫草雕。你可以給這些遠端取任何名字巷屿,約定的做法是將origin作為你fork后的倉庫的遠端(運行git clone是會自動創(chuàng)建)和upstream作為官方項目。
git remote add upstream https://github.com/maintainer/repo

你需要使用上面的命令來創(chuàng)建上游倉庫的遠程連接墩虹。它使得你輕易地保持本地倉庫和官方倉庫的進展同步嘱巾。注意如果你的上游倉庫開啟了認證(比如它沒有開源),你需要提供一個用戶名诫钓,就像這樣:
git remote add upstream https://user@bitbucket.org/maintainer/repo.git

它需要用戶從官方代碼庫克隆或拉取之前提供有效的密碼旬昭。
開發(fā)者進行自己的開發(fā)

在他們剛克隆的本地倉庫中,開發(fā)者可以編輯代碼菌湃、提交更改问拘,和其它分支中一樣######創(chuàng)建分支:
git checkout -b some-feature# 編輯代碼git commit -a -m "Add first draft of some feature"

他們所有的更改在推送到公開倉庫之前都是完全私有的。而且慢味,如果官方項目已經(jīng)向前進展了,他們可以用git pull獲取新的提交:
git pull upstream master

因為開發(fā)者應該在專門的功能分支開發(fā)墅冷,這一般會產(chǎn)生一個快速向前的合并纯路。

開發(fā)者發(fā)布他們的功能

一旦開發(fā)者準備好共享他們的新功能,他們需要做兩件事情寞忿。第一驰唬,他們必須將貢獻的代碼推送到自己的公開倉庫,讓其他開發(fā)者能夠訪問到腔彰。他們的origin遠端應該已經(jīng)設置好了叫编,所以他們只需要:
git push origin feature-branch

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

第二,他們需要通知項目維護者杯拐,他們想要將功能并入官方代碼庫霞篡。Github提供了一個“New Pull Request”按鈕,跳轉到一個網(wǎng)頁端逼,讓你指明想要并入主倉庫的分支朗兵。一般來說,你希望將功能分支并入上游遠端的master分支顶滩。

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

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

將代碼拉取到本地倉庫然后手動合并

第一個選項更簡單礁鲁,讓維護者查看修改前后的差異盐欺,在上面評論赁豆,然后通過圖形界面執(zhí)行合并。然而找田,如果pull request會導致合并沖突歌憨,第二個選項就有了必要。在這個情況中墩衙,維護者需要從開發(fā)者的服務端倉庫fetch功能分支务嫡,合并到他們本地的master分支,然后解決沖突:
git fetch https://bitbucket.org/user/repo feature-branch# 檢查修改git checkout mastergit merge FETCH_HEAD

一旦修改被整合進本地的master漆改,維護者需要將它推送到服務器上的官方倉庫心铃,這樣其他開發(fā)者也可以訪問它:
git push origin master

記住,維護者的origin指向他們的公開倉庫挫剑,也就是項目的官方代碼庫去扣。開發(fā)者的貢獻現(xiàn)在完全并入了項目。

開發(fā)者和中央倉庫保持同步

因為主代碼庫已經(jīng)取得了新的進展樊破,其他開發(fā)者應該和官方倉庫同步:
git pull upstream master

接下來該怎么做

如果你從SVN遷移而來愉棱,F(xiàn)ork工作流看上去是一個比較大的轉變。但不要害怕——它只是在Feature分支工作流之上引入了一層抽象哲戚。貢獻的代碼發(fā)布到開發(fā)者在服務端自己的倉庫奔滑,而不是在唯一的中央倉庫中直接共享分支。

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

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市几蜻,隨后出現(xiàn)的幾起案子癞松,更是在濱河造成了極大的恐慌,老刑警劉巖入蛆,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件响蓉,死亡現(xiàn)場離奇詭異,居然都是意外死亡哨毁,警方通過查閱死者的電腦和手機枫甲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人想幻,你說我怎么就攤上這事粱栖。” “怎么了脏毯?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵闹究,是天一觀的道長。 經(jīng)常有香客問我食店,道長渣淤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任吉嫩,我火速辦了婚禮价认,結果婚禮上,老公的妹妹穿的比我還像新娘自娩。我一直安慰自己用踩,他們只是感情好,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布忙迁。 她就那樣靜靜地躺著脐彩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪姊扔。 梳的紋絲不亂的頭發(fā)上惠奸,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音旱眯,去河邊找鬼晨川。 笑死证九,一個胖子當著我的面吹牛删豺,可吹牛的內容都是我干的。 我是一名探鬼主播愧怜,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼呀页,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拥坛?” 一聲冷哼從身側響起蓬蝶,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎猜惋,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡悬襟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年管闷,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡禾锤,死狀恐怖私股,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情恩掷,我是刑警寧澤倡鲸,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站黄娘,受9級特大地震影響峭状,放射性物質發(fā)生泄漏。R本人自食惡果不足惜寸宏,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一宁炫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧氮凝,春花似錦羔巢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至稿壁,卻和暖如春幽钢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背傅是。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工匪燕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喧笔。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓帽驯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親书闸。 傳聞我的和親對象是個殘疾皇子尼变,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內容

  • 從開始到現(xiàn)在牌借,想你的時數(shù)不斷增多度气。我只希望你過得好。在那些我們一起走過的歲月里膨报,已經(jīng)成為我生命中的一部分磷籍,可你早已...
    桌孔閱讀 164評論 0 0
  • 國慶前夕哲虾,很多朋友都慢慢的接著放假了,對于一年里為數(shù)不多的長假择示,還沒開始前束凑,總是期待著有些什么美好會發(fā)生,就好像它...
    TSFH閱讀 165評論 0 0
  • 從大一進入校報,就開始過記者節(jié)谈秫,今年正巧趕上第18個記者節(jié)扒寄,也是我過的第8個記者節(jié)。 起初拟烫,我只是喜歡寫文章该编,或者...
    黎茉閱讀 271評論 0 1
  • 我本性善良。 我是一名在醫(yī)院實習小護士硕淑。 這是我在醫(yī)院實習的第十一個月课竣,論起來也算是老資格實習...
    翻滾的蝸小牛閱讀 511評論 1 2