本文轉載自github:git-workflow-tutorialhtml
我的在學習Git
工做流的過程當中,從原有的 SVN 模式很難徹底理解Git
的協做模式,直到有一天我看到了下面的文章,好多遺留在心中的困惑迎刃而解:git
Git
有什麼不妥?Git
方便的branch在哪裏,團隊多人如何協做?衝突了怎麼辦?如何進行發佈控制?GitHub
上面與他人一塊兒協做,star-fork-pull request是怎樣的流程?我我的很感激這篇文章,因此進行了整理,但願能幫到更多的人。整篇文章由 xirong 整理自 oldratlee 的GitHub
,方便統一的學習回顧,在此感謝下面兩位的貢獻。github
原文連接:Git Workflows and Tutorials
簡體中文:由 oldratlee 翻譯在 GitHub
上 Git
工做流指南安全
在第三部分 企業平常開發模式探索 ,結合本身所在公司使用git的版本分支開發過程,進行了總結,歡迎你們提出更好的建議。bash
這篇指南以你們在SVN
中已經廣爲熟悉使用的集中式工做流做爲起點,按部就班地演進到其它高效的分佈式工做流,還介紹瞭如何配合使用便利的Pull Request
功能,體系地講解了各類工做流的應用。
若是你Git
用的還很少,能夠從前面的講的工做流開始操練。操做過程去感覺指南的講解:解決什麼問題、如何解決問題,這樣理解就深了,也方便活用。服務器
行文中實踐原則和操做示例並重,對於Git
的資深玩家能夠梳理思考提高,而新接觸的同窗,也能夠跟着step-by-step操練學習並在實際工做中上手使用。併發
工做流其實不是一個初級主題,背後的本質問題實際上是 有效的項目流程管理 和 高效的開發協同約定,而不只是Git
或SVN
等VCS
或SCM
工具的使用。app
關於Git
工做流主題,網上體系的中文資料很少,主要是零散的操做說明,但願這篇文章能讓你更深刻理解並在工做中靈活有效地使用起來。框架
Gitflow
工做流是經典模型,處於核心位置,體現了工做流的經驗和精髓。隨着項目過程複雜化,你會感覺到這個工做流中的深思熟慮和威力!ssh
Forking
工做流是分佈式協做的(GitHub
風格)能夠先看看GitHub
的Help:Fork A Repo和Using pull requests 。照着操做,給一個GitHub
項目貢獻你的提交,有操做經驗再看指南容易意會。指南中給了本身實現Fork
的方法:Fork
就是服務端的克隆。在指南的操練中使用代碼託管服務(如GitHub
、Bitbucket
),能夠點一下按鈕就讓開發者完成倉庫的fork
操做。
PS:
文中Pull Request
的介紹用的是Bitbucket
代碼託管服務,因爲和GitHub
基本同樣,若是你用的是GitHub
(我本身也主要使用GitHub
託管代碼),不影響理解和操做。
PPS:
更多Git
學習資料參見
Git
工做流指南 工做流有各式各樣的用法,但也正所以使得在實際工做中如何上手使用變得很頭大。這篇指南經過總覽公司團隊中最經常使用的幾種Git
工做流讓你們能夠上手使用。
在閱讀的過程當中請記住,本文中的幾種工做流是做爲方案指導而不是條例規定。在展現了各類工做流可能的用法後,你能夠從不一樣的工做流中挑選或揉合出一個知足你本身需求的工做流。
若是你的開發團隊成員已經很熟悉Subversion
,集中式工做流讓你無需去適應一個全新流程就能夠體驗Git
帶來的收益。這個工做流也能夠做爲向更Git
風格工做流遷移的友好過渡。
轉到分佈式版本控制系統看起來像個使人生畏的任務,但不改變已用的工做流你也能夠用上Git
帶來的收益。團隊能夠用和Subversion
徹底不變的方式來開發項目。
但使用Git
增強開發的工做流,Git
有相比SVN
的幾個優點。
首先,每一個開發能夠有屬於本身的整個工程的本地拷貝。隔離的環境讓各個開發者的工做和項目的其餘部分修改獨立開來 ——
即自由地提交到本身的本地倉庫,先徹底忽略上游的開發,直到方便的時候再把修改反饋上去。
其次,Git
提供了強壯的分支和合並模型。不像SVN
,Git
的分支設計成能夠作爲一種用來在倉庫之間集成代碼和分享修改的『失敗安全』的機制。
像Subversion
同樣,集中式工做流以中央倉庫做爲項目全部修改的單點實體。相比SVN
缺省的開發分支trunk
,Git
叫作master
,全部修改提交到這個分支上。本工做流只用到master
這一個分支。
開發者開始先克隆中央倉庫。在本身的項目拷貝中像SVN
同樣的編輯文件和提交修改;但修改是存在本地的,和中央倉庫是徹底隔離的。開發者能夠把和上游的同步延後到一個方便時間點。
要發佈修改到正式項目中,開發者要把本地master
分支的修改『推』到中央倉庫中。這至關於svn commit
操做,但push
操做會把全部還不在中央倉庫的本地提交都推上去。
中央倉庫表明了正式項目,因此提交歷史應該被尊重且是穩定不變的。若是開發者本地的提交歷史和中央倉庫有分歧,Git
會拒絕push
提交不然會覆蓋已經在中央庫的正式提交。
在開發者提交本身功能修改到中央庫前,須要先fetch
在中央庫的新增提交,rebase
本身提交到中央庫提交歷史之上。
這樣作的意思是在說,『我要把本身的修改加到別人已經完成的修改上。』最終的結果是一個完美的線性歷史,就像之前的SVN
的工做流中同樣。
若是本地修改和上游提交有衝突,Git
會暫停rebase
過程,給你手動解決衝突的機會。Git
解決合併衝突,用和生成提交同樣的git status
和git add
命令,很一致方便。還有一點,若是解決衝突時遇到麻煩,Git
能夠很簡單停止整個rebase
操做,重來一次(或者讓別人來幫助解決)。
讓咱們一塊兒逐步分解來看看一個常見的小團隊如何用這個工做流來協做的。有兩個開發者小明和小紅,看他們是如何開發本身的功能並提交到中央倉庫上的。
第一步,有人在服務器上建立好中央倉庫。若是是新項目,你能夠初始化一個空倉庫;不然你要導入已有的Git
或SVN
倉庫。
中央倉庫應該是個裸倉庫(bare repository
),即沒有工做目錄(working directory
)的倉庫。能夠用下面的命令建立:
ssh user@host git init --bare /path/to/repo.git
確保寫上有效的user
(SSH
的用戶名),host
(服務器的域名或IP地址),/path/to/repo.git
(你想存放倉庫的位置)。
注意,爲了表示是一個裸倉庫,按照約定加上.git
擴展名到倉庫名上。
下一步,各個開發者建立整個項目的本地拷貝。經過git clone
命令完成:
git clone ssh://user@host/path/to/repo.git
基於你後續會持續和克隆的倉庫作交互的假設,克隆倉庫時Git
會自動添加遠程別名origin
指回『父』倉庫。
在小明的本地倉庫中,他使用標準的Git
過程開發功能:編輯、暫存(Stage
)和提交。
若是你不熟悉暫存區(Staging Area
),這裏說明一下:暫存區用來準備一個提交,但能夠不用把工做目錄中全部的修改內容都包含進來。
這樣你能夠建立一個高度聚焦的提交,儘管你本地修改不少內容。
git status # 查看本地倉庫的修改狀態 git add # 暫存文件 git commit # 提交文件
請記住,由於這些命令生成的是本地提交,小明能夠按本身需求反覆操做屢次,而不用擔憂中央倉庫上有了什麼操做。
對須要多個更簡單更原子分塊的大功能,這個作法是頗有用的。
與此同時,小紅在本身的本地倉庫中用相同的編輯、暫存和提交過程開發功能。和小明同樣,她也不關心中央倉庫有沒有新提交;
固然更不關心小明在他的本地倉庫中的操做,由於全部本地倉庫都是私有的。
一旦小明完成了他的功能開發,會發布他的本地提交到中央倉庫中,這樣其它團隊成員能夠看到他的修改。他能夠用下面的git push
命令:
git push origin master
注意,origin
是在小明克隆倉庫時Git
建立的遠程中央倉庫別名。master
參數告訴Git
推送的分支。
因爲中央倉庫自從小明克隆以來尚未被更新過,因此push
操做不會有衝突,成功完成。
一塊兒來看看在小明發布修改後,小紅push
修改會怎麼樣?她使用徹底同樣的push
命令:
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.
這避免了小紅覆寫正式的提交。她要先pull
小明的更新到她的本地倉庫合併上她的本地修改後,再重試。
rebase
小紅用git pull
合併上游的修改到本身的倉庫中。
這條命令相似svn update
——拉取全部上游提交命令到小紅的本地倉庫,並嘗試和她的本地修改合併:
git pull --rebase origin master
--rebase
選項告訴Git
把小紅的提交移到同步了中央倉庫修改後的master
分支的頂部,以下圖所示:
若是你忘加了這個選項,pull
操做仍然能夠完成,但每次pull
操做要同步中央倉庫中別人修改時,提交歷史會以一個多餘的『合併提交』結尾。
對於集中式工做流,最好是使用rebase
而不是生成一個合併提交。
rebase
操做過程是把本地提交一次一個地遷移到更新了的中央倉庫master
分支之上。
這意味着可能要解決在遷移某個提交時出現的合併衝突,而不是解決包含了全部提交的大型合併時所出現的衝突。
這樣的方式讓你儘量保持每一個提交的聚焦和項目歷史的整潔。反過來,簡化了哪裏引入Bug
的分析,若是有必要,回滾修改也能夠作到對項目影響最小。
若是小紅和小明的功能是不相關的,不大可能在rebase
過程當中有衝突。若是有,Git
在合併有衝突的提交處暫停rebase
過程,輸出下面的信息並帶上相關的指令:
CONFLICT (content): Merge conflict in <some-file>
Git
很讚的一點是,任何人能夠解決他本身的衝突。在這個例子中,小紅能夠簡單的運行git status
命令來查看哪裏有問題。
衝突文件列在Unmerged paths
(未合併路徑)一節中:
# 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 pull --rebase
命令前的樣子:
git rebase --abort
小紅完成和中央倉庫的同步後,就能成功發佈她的修改了:
git push origin master
如你所見,僅使用幾個Git
命令咱們就能夠模擬出傳統Subversion
開發環境。對於要從SVN
遷移過來的團隊來講這太好了,但沒有發揮出Git
分佈式本質的優點。
若是你的團隊適應了集中式工做流,但想要更流暢的協做效果,絕對值得探索一下 功能分支工做流
的收益。
經過爲一個功能分配一個專門的分支,可以作到一個新增功能集成到正式項目以前對新功能進行深刻討論。
功能分支工做流以集中式工做流爲基礎,不一樣的是爲各個新功能分配一個專門的分支來開發。這樣能夠在把新功能集成到正式項目前,用Pull Requests
的方式討論變動。
一旦你玩轉了集中式工做流,在開發過程當中能夠很簡單地加上功能分支,用來鼓勵開發者之間協做和簡化交流。
功能分支工做流背後的核心思路是全部的功能開發應該在一個專門的分支,而不是在master
分支上。
這個隔離能夠方便多個開發者在各自的功能上開發而不會弄亂主幹代碼。
另外,也保證了master
分支的代碼必定不會是有問題的,極大有利於集成環境。
功能開發隔離也讓pull requests
工做流成功可能,pull requests
工做流能爲每一個分支發起一個討論,在分支合入正式項目以前,給其它開發者有表示贊同的機會。
另外,若是你在功能開發中有問題卡住了,能夠開一個pull requests
來向同窗們徵求建議。
這些作法的重點就是,pull requests
讓團隊成員之間互相評論工做變成很是方便!
功能分支工做流仍然用中央倉庫,而且master
分支仍是表明了正式項目的歷史。
但不是直接提交本地歷史到各自的本地master
分支,開發者每次在開始新功能前先建立一個新分支。
功能分支應該有個有描述性的名字,好比animated-menu-items
或issue-#1061
,這樣可讓分支有個清楚且高聚焦的用途。
在master
分支和功能分支之間,Git
是沒有技術上的區別,因此開發者能夠用和集中式工做流中徹底同樣的方式編輯、暫存和提交修改到功能分支上。
另外,功能分支也能夠(且應該)push
到中央倉庫中。這樣不修改正式代碼就能夠和其它開發者分享提交的功能。
因爲master
是僅有的一個『特殊』分支,在中央倉庫上存多個功能分支不會有任何問題。固然,這樣作也能夠很方便地備份各自的本地提交。
Pull Requests
功能分支除了能夠隔離功能的開發,也使得經過Pull Requests
討論變動成爲可能。
一旦某個開發完成一個功能,不是當即合併到master
,而是push
到中央倉庫的功能分支上併發起一個Pull Request
請求去合併修改到master
。
在修改爲爲主幹代碼前,這讓其它的開發者有機會先去Review
變動。
Code Review
是Pull Requests
的一個重要的收益,但Pull Requests
目的是討論代碼一個通用方式。
你能夠把Pull Requests
做爲專門給某個分支的討論。這意味着能夠在更早的開發過程當中就能夠進行Code Review
。
好比,一個開發者開發功能須要幫助時,要作的就是發起一個Pull Request
,相關的人就會自動收到通知,在相關的提交旁邊能看到須要幫助解決的問題。
一旦Pull Request
被接受了,發佈功能要作的就和集中式工做流就很像了。
首先,肯定本地的master
分支和上游的master
分支是同步的。而後合併功能分支到本地master
分支並push
已經更新的本地master
分支到中央倉庫。
倉庫管理的產品解決方案像Bitbucket
或Stash
,能夠良好地支持Pull Requests
。能夠看看Stash
的Pull Requests
文檔。
下面的示例演示瞭如何把Pull Requests
做爲Code Review
的方式,但注意Pull Requests
能夠用於不少其它的目的。
在開始開發功能前,小紅須要一個獨立的分支。使用下面的命令新建一個分支:
git checkout -b marys-feature master
這個命令檢出一個基於master
名爲marys-feature
的分支,Git
的-b
選項表示若是分支還不存在則新建分支。
這個新分支上,小紅按老套路編輯、暫存和提交修改,按須要提交以實現功能:
git status git add <some-file> git commit
早上小紅爲新功能添加一些提交。
去吃午餐前,push
功能分支到中央倉庫是很好的作法,這樣能夠方便地備份,若是和其它開發協做,也讓他們能夠看到小紅的提交。
git push -u origin marys-feature
這條命令push
marys-feature
分支到中央倉庫(origin
),-u
選項設置本地分支去跟蹤遠程對應的分支。
設置好跟蹤的分支後,小紅就可使用git push
命令省去指定推送分支的參數。
小紅吃完午餐回來,完成整個功能的開發。在合併到master
以前,
她發起一個Pull Request
讓團隊的其它人知道功能已經完成。但首先,她要確認中央倉庫中已經有她最近的提交:
git push
而後,在她的Git
GUI
客戶端中發起Pull Request
,請求合併marys-feature
到master
,團隊成員會自動收到通知。Pull Request
很酷的是能夠在相關的提交旁邊顯示評註,因此你能夠對某個變動集提問。
Pull Request
小黑收到了Pull Request
後會查看marys-feature
的修改。決定在合併到正式項目前是否要作些修改,且經過Pull Request
和小紅來回地討論。
要再作修改,小紅用和功能第一個迭代徹底同樣的過程。編輯、暫存、提交併push
更新到中央倉庫。小紅這些活動都會顯示在Pull Request
上,小黑能夠斷續作評註。
若是小黑有須要,也能夠把marys-feature
分支拉到本地,本身來修改,他加的提交也會同樣顯示在Pull Request
上。
一旦小黑能夠的接受Pull Request
,就能夠合併功能到穩定項目代碼中(能夠由小黑或是小紅來作這個操做):
git checkout master git pull git pull origin marys-feature git push
不管誰來作合併,首先要檢出master
分支並確認是它是最新的。而後執行git pull origin marys-feature
合併marys-feature
分支到和已經和遠程一致的本地master
分支。
你可使用簡單git merge marys-feature
命令,但前面的命令能夠保證老是最新的新功能分支。
最後更新的master
分支要從新push
回到origin
。
這個過程經常會生成一個合併提交。有些開發者喜歡有合併提交,由於它像一個新功能和原來代碼基線的連通符。
但若是你偏心線性的提交歷史,能夠在執行合併時rebase
新功能到master
分支的頂部,這樣生成一個快進(fast-forward
)的合併。
一些GUI
客戶端能夠只要點一下『接受』按鈕執行好上面的命令來自動化Pull Request
接受過程。
若是你的不能這樣,至少在功能合併到master
分支後能自動關閉Pull Request
。
當小紅和小黑在marys-feature
上工做並討論她的Pull Request
的時候,小明在本身的功能分支上作徹底同樣的事。
經過隔離功能到獨立的分支上,每一個人均可以自主的工做,固然必要的時候在開發者之間分享變動仍是比較繁瑣的。
到了這裏,希望你發現了功能分支能夠很直接地在 集中式工做流
的僅有的master
分支上完成多功能的開發。
另外,功能分支還使用了Pull Request
,使得能夠在你的版本控制GUI
客戶端中討論某個提交。
功能分支工做流是開發項目異常靈活的方式。問題是,有時候太靈活了。對於大型團隊,經常須要給不一樣分支分配一個更具體的角色。Gitflow
工做流是管理功能開發、發佈準備和維護的經常使用模式。
Gitflow
工做流Gitflow
工做流經過爲功能開發、發佈準備和維護分配獨立的分支,讓發佈迭代過程更流暢。嚴格的分支模型也爲大型項目提供了一些很是必要的結構。
這節介紹的Gitflow
工做流借鑑自在nvie的Vincent Driessen。
Gitflow
工做流定義了一個圍繞項目發佈的嚴格分支模型。雖然比功能分支工做流複雜幾分,但提供了用於一個健壯的用於管理大型項目的框架。
Gitflow
工做流沒有用超出功能分支工做流的概念和命令,而是爲不一樣的分支分配一個很明確的角色,並定義分支之間如何和何時進行交互。
除了使用功能分支,在作準備、維護和記錄發佈也使用各自的分支。
固然你能夠用上功能分支工做流全部的好處:Pull Requests
、隔離實驗性開發和更高效的協做。
Gitflow
工做流仍然用中央倉庫做爲全部開發者的交互中心。和其它的工做流同樣,開發者在本地工做並push
分支到要中央倉庫中。
相對使用僅有的一個master
分支,Gitflow
工做流使用2個分支來記錄項目的歷史。master
分支存儲了正式發佈的歷史,而develop
分支做爲功能的集成分支。
這樣也方便master
分支上的全部提交分配一個版本號。
剩下要說明的問題圍繞着這2個分支的區別展開。
每一個新功能位於一個本身的分支,這樣能夠push
到中央倉庫以備份和協做。
但功能分支不是從master
分支上拉出新分支,而是使用develop
分支做爲父分支。當新功能完成時,合併回develop
分支。
新功能提交應該從不直接與master
分支交互。
注意,從各類含義和目的上來看,功能分支加上develop
分支就是功能分支工做流的用法。但Gitflow
工做流沒有在這裏止步。
一旦develop
分支上有了作一次發佈(或者說快到了既定的發佈日)的足夠功能,就從develop
分支上checkout
一個發佈分支。
新建的分支用於開始發佈循環,因此從這個時間點開始以後新的功能不能再加到這個分支上——
這個分支只應該作Bug
修復、文檔生成和其它面向發佈任務。
一旦對外發布的工做都完成了,發佈分支合併到master
分支並分配一個版本號打好Tag
。
另外,這些重新建發佈分支以來的作的修改要合併回develop
分支。
使用一個用於發佈準備的專門分支,使得一個團隊能夠在完善當前的發佈版本的同時,另外一個團隊能夠繼續開發下個版本的功能。
這也打造定義良好的開發階段(好比,能夠很輕鬆地說,『這周咱們要作準備發佈版本4.0』,而且在倉庫的目錄結構中能夠實際看到)。
經常使用的分支約定:
用於新建發佈分支的分支: develop 用於合併的分支: master 分支命名: release-* 或 release/*
維護分支或說是熱修復(hotfix
)分支用於生成快速給產品發佈版本(production releases
)打補丁,這是惟一能夠直接從master
分支fork
出來的分支。
修復完成,修改應該立刻合併回master
分支和develop
分支(當前的發佈分支),master
分支應該用新的版本號打好Tag
。
爲Bug
修復使用專門分支,讓團隊能夠處理掉問題而不用打斷其它工做或是等待下一個發佈循環。
你能夠把維護分支想成是一個直接在master
分支上處理的臨時發佈。
下面的示例演示本工做流如何用於管理單個發佈循環。假設你已經建立了一箇中央倉庫。
第一步爲master
分支配套一個develop
分支。簡單來作能夠本地建立一個空的develop
分支,push
到服務器上:
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
如今每一個開發都有了這些歷史分支的本地拷貝。
這個示例中,小紅和小明開始各自的功能開發。他們須要爲各自的功能建立相應的分支。新分支不是基於master
分支,而是應該基於develop
分支:
git checkout -b some-feature develop
他們用老套路添加提交到各自功能分支上:編輯、暫存、提交:
git status git add <some-file> git commit
添加了提交後,小紅以爲她的功能OK了。若是團隊使用Pull Requests
,這時候能夠發起一個用於合併到develop
分支。
不然她能夠直接合併到她本地的develop
分支後push
到中央倉庫:
git pull origin develop git checkout develop git merge some-feature git push git branch -d some-feature
第一條命令在合併功能前確保develop
分支是最新的。注意,功能決不該該直接合併到master
分支。
衝突解決方法和集中式工做流同樣。
這個時候小明正在實現他的功能,小紅開始準備她的第一個項目正式發佈。
像功能開發同樣,她用一個新的分支來作發佈準備。這一步也肯定了發佈的版本號:
git checkout -b release-0.1 develop
這個分支是清理髮布、執行全部測試、更新文檔和其它爲下個發佈作準備操做的地方,像是一個專門用於改善發佈的功能分支。
只要小紅建立這個分支並push
到中央倉庫,這個發佈就是功能凍結的。任何不在develop
分支中的新功能都推到下個發佈循環中。
一旦準備好了對外發布,小紅合併修改到master
分支和develop
分支上,刪除發佈分支。合併回develop
分支很重要,由於在發佈分支中已經提交的更新須要在後面的新功能中也要是可用的。
另外,若是小紅的團隊要求Code Review
,這是一個發起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
分支,就應該打好Tag
以方便跟蹤。
git tag -a 0.1 -m "Initial public release" master git push --tags
Git
有提供各類勾子(hook
),即倉庫有事件發生時觸發執行的腳本。
能夠配置一個勾子,在你push
中央倉庫的master
分支時,自動構建好對外發布。
Bug
對外發布後,小紅回去和小明一塊兒作下個發佈的新功能開發,直到有最終用戶開了一個Ticket
抱怨當前版本的一個Bug
。
爲了處理Bug
,小紅(或小明)從master
分支上拉出了一個維護分支,提交修改以解決問題,而後直接合並回master
分支:
git checkout -b issue-#001 master # Fix the bug git checkout master git merge issue-#001 git push
就像發佈分支,維護分支中新加這些重要修改須要包含到develop
分支中,因此小紅要執行一個合併操做。而後就能夠安全地刪除這個分支了:
git checkout develop git merge issue-#001 git push git branch -d issue-#001
到了這裏,希望你對集中式工做流、功能分支工做流和Gitflow
工做流已經感受很溫馨了。
你應該也牢固的掌握了本地倉庫的潛能,push
/pull
模式和Git
健壯的分支和合並模型。
記住,這裏演示的工做流只是可能用法的例子,而不是在實際工做中使用Git
不可違逆的條例。
因此不要畏懼按本身須要對工做流的用法作取捨。不變的目標就是讓Git
爲你所用。
Forking
工做流Forking
工做流是分佈式工做流,充分利用了Git
在分支和克隆上的優點。能夠安全可靠地管理大團隊的開發者(developer
),並能接受不信任貢獻者(contributor
)的提交。
Forking
工做流和前面討論的幾種工做流有根本的不一樣,這種工做流不是使用單個服務端倉庫做爲『中央』代碼基線,而讓各個開發者都有一個服務端倉庫。這意味着各個代碼貢獻者有2個Git
倉庫而不是1個:一個本地私有的,另外一個服務端公開的。
Forking
工做流的一個主要優點是,貢獻的代碼能夠被集成,而不須要全部人都能push
代碼到僅有的中央倉庫中。
開發者push
到本身的服務端倉庫,而只有項目維護者才能push
到正式倉庫。
這樣項目維護者能夠接受任何開發者的提交,但無需給他正式代碼庫的寫權限。
效果就是一個分佈式的工做流,能爲大型、自發性的團隊(包括了不受信的第三方)提供靈活的方式來安全的協做。
也讓這個工做流成爲開源項目的理想工做流。
和其它的Git
工做流同樣,Forking
工做流要先有一個公開的正式倉庫存儲在服務器上。
但一個新的開發者想要在項目上工做時,不是直接從正式倉庫克隆,而是fork
正式項目在服務器上建立一個拷貝。
這個倉庫拷貝做爲他我的公開倉庫 ——
其它開發者不容許push
到這個倉庫,但能夠pull
到修改(後面咱們很快就會看這點很重要)。
在建立了本身服務端拷貝以後,和以前的工做流同樣,開發者執行git clone
命令克隆倉庫到本地機器上,做爲私有的開發環境。
要提交本地修改時,push
提交到本身公開倉庫中 —— 而不是正式倉庫中。
而後,給正式倉庫發起一個pull request
,讓項目維護者知道有更新已經準備好能夠集成了。
對於貢獻的代碼,pull request
也能夠很方便地做爲一個討論的地方。
爲了集成功能到正式代碼庫,維護者pull
貢獻者的變動到本身的本地倉庫中,檢查變動以確保不會讓項目出錯,
合併變動到本身本地的master
分支,
而後push
master
分支到服務器的正式倉庫中。
到此,貢獻的提交成爲了項目的一部分,其它的開發者應該執行pull
操做與正式倉庫同步本身本地倉庫。
在Forking
工做流中,『官方』倉庫的叫法只是一個約定,理解這點很重要。
從技術上來看,各個開發者倉庫和正式倉庫在Git
看來沒有任何區別。
事實上,讓正式倉庫之因此正式的惟一緣由是它是項目維護者的公開倉庫。
Forking
工做流的分支使用方式全部的我的公開倉庫實際上只是爲了方便和其它的開發者共享分支。
各個開發者應該用分支隔離各個功能,就像在功能分支工做流和Gitflow
工做流同樣。
惟一的區別是這些分支被共享了。在Forking
工做流中這些分支會被pull
到另外一個開發者的本地倉庫中,而在功能分支工做流和Gitflow
工做流中是直接被push
到正式倉庫中。
和任何使用Git
項目同樣,第一步是建立在服務器上一個正式倉庫,讓全部團隊成員均可以訪問到。
一般這個倉庫也會做爲項目維護者的公開倉庫。
公開倉庫應該是裸倉庫,無論是否是正式代碼庫。
因此項目維護者會運行像下面的命令來搭建正式倉庫:
ssh user@host git init --bare /path/to/repo.git
Bitbucket
和Stash
提供了一個方便的GUI
客戶端以完成上面命令行作的事。
這個搭建中央倉庫的過程和前面提到的工做流徹底同樣。
若是有現存的代碼庫,維護者也要push
到這個倉庫中。
fork
正式倉庫其它全部的開發須要fork
正式倉庫。
能夠用git clone
命令用SSH
協議連通到服務器,
拷貝倉庫到服務器另外一個位置 —— 是的,fork
操做基本上就只是一個服務端的克隆。Bitbucket
和Stash
上能夠點一下按鈕就讓開發者完成倉庫的fork
操做。
這一步完成後,每一個開發都在服務端有一個本身的倉庫。和正式倉庫同樣,這些倉庫應該是裸倉庫。
fork
出來的倉庫下一步,各個開發者要克隆本身的公開倉庫,用熟悉的git clone
命令。
在這個示例中,假定用Bitbucket
託管了倉庫。記住,若是這樣的話各個開發者須要有各自的Bitbucket
帳號,
使用下面命令克隆服務端本身的倉庫:
git clone https://user@bitbucket.org/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://user@bitbucket.org/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
遠程別名指向開發者本身的服務端倉庫,而不是正式倉庫。
第二件事,開發者要通知項目維護者,想要合併他的新功能到正式庫中。Bitbucket
和Stash
提供了Pull Request
按鈕,彈出表單讓你指定哪一個分支要合併到正式倉庫。
通常你會想集成你的功能分支到上游遠程倉庫的master
分支中。
當項目維護者收到pull request
,他要作的是決定是否集成它到正式代碼庫中。有二種方式來作:
pull request
中查看代碼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
若是你以前是使用SVN
,Forking
工做流可能看起來像是一個激進的範式切換(paradigm shift)。
但不要懼怕,這個工做流實際上就是在功能分支工做流之上引入另外一個抽象層。
不是直接經過單箇中央倉庫來分享分支,而是把貢獻代碼發佈到開發者本身的服務端倉庫中。
示例中解釋了,一個貢獻如何從一個開發者流到正式的master
分支中,但一樣的方法能夠把貢獻集成到任一個倉庫中。
好比,若是團隊的幾我的協做實現一個功能,能夠在開發之間用相同的方法分享變動,徹底不涉及正式倉庫。
這使得Forking
工做流對於鬆散組織的團隊來講是個很是強大的工具。任一開發者能夠方便地和另外一開發者分享變動,任何分支都能有效地合併到正式代碼庫中。
Pull Requests
Pull requests
是Bitbucket
提供的讓開發者更方便地進行協做的功能,提供了友好的Web
界面能夠在提議的修改合併到正式項目以前對修改進行討論。
開發者向團隊成員通知功能開發已經完成,Pull Requests
是最簡單的用法。
開發者完成功能開發後,經過Bitbucket
帳號發起一個Pull Request
。
這樣讓涉及這個功能的全部人知道要去作Code Review
和合併到master
分支。
可是,Pull Request
遠不止一個簡單的通知,而是爲討論提交的功能的一個專門論壇。
若是變動有任何問題,團隊成員反饋在Pull Request
中,甚至push
新的提交微調功能。
全部的這些活動都直接跟蹤在Pull Request
中。
相比其它的協做模型,這種分享提交的形式有助於打造一個更流暢的工做流。SVN
和Git
都能經過一個簡單的腳本收到通知郵件;可是,討論變動時,開發者一般只能去回覆郵件。
這樣作會變得雜亂,尤爲還要涉及後面的幾個提交時。Pull Requests
把全部相關功能整合到一個和Bitbucket
倉庫界面集成的用戶友好Web
界面中。
Pull Request
當要發起一個Pull Request
,你所要作的就是請求(Request
)另外一個開發者(好比項目的維護者)
來pull
你倉庫中一個分支到他的倉庫中。這意味着你要提供4個信息以發起Pull Request
:
源倉庫、源分支、目的倉庫、目的分支。
這幾值多數Bitbucket
都會設置上合適的缺省值。但取決你用的協做工做流,你的團隊可能會要指定不一樣的值。
上圖顯示了一個Pull Request
請求合併一個功能分支到正式的master
分支上,但能夠有多種不一樣的Pull Request
用法。
Pull Request
能夠和功能分支工做流、Gitflow
工做流或Forking
工做流一塊兒使用。
但一個Pull Request
要求要麼分支不一樣要麼倉庫不一樣,因此不能用於集中式工做流。
在不一樣的工做流中使用Pull Request
會有一些不一樣,但基本的過程是這樣的:
push
分支修改到公開的Bitbucket
倉庫中。Bitbucket
發起一個Pull Request
。review
code
,討論並修改。Pull Request
。本文後面內容說明,Pull Request
在不一樣協做工做流中如何應用。
Pull Request
功能分支工做流用一個共享的Bitbucket
倉庫來管理協做,開發者在專門的分支上開發功能。
但不是當即合併到master
分支上,而是在合併到主代碼庫以前開發者應該開一個Pull Request
發起功能的討論。
功能分支工做流只有一個公開的倉庫,因此Pull Request
的目的倉庫和源倉庫老是同一個。
一般開發者會指定他的功能分支做爲源分支,master
分支做爲目的分支。
收到Pull Request
後,項目維護者要決定如何作。若是功能沒問題,就簡單地合併到master
分支,關閉Pull Request
。
但若是提交的變動有問題,他能夠在Pull Request
中反饋。以後新加的提交也會評論以後接着顯示出來。
在功能尚未徹底開發完的時候,也可能發起一個Pull Request
。
好比開發者在實現某個需求時碰到了麻煩,他能夠發一個包含正在進行中工做的Pull Request
。
其它的開發者能夠在Pull Request
提供建議,或者甚至直接添加提交來解決問題。
Gitflow
工做流中使用Pull Request
Gitflow
工做流和功能分支工做流相似,但圍繞項目發佈定義一個嚴格的分支模型。
在Gitflow
工做流中使用Pull Request
讓開發者在發佈分支或是維護分支上工做時,
能夠有個方便的地方對關於發佈分支或是維護分支的問題進行交流。
Gitflow
工做流中Pull Request
的使用過程和上一節中徹底一致:
當一個功能、發佈或是熱修復分支須要Review
時,開發者簡單發起一個Pull Request
,
團隊的其它成員會經過Bitbucket
收到通知。
新功能通常合併到develop
分支,而發佈和熱修復則要同時合併到develop
分支和master
分支上。Pull Request
可能用作全部合併的正式管理。
Forking
工做流中使用Pull Request
在Forking
工做流中,開發者push
完成的功能到他本身的倉庫中,而不是共享倉庫。
而後,他發起一個Pull Request
,讓項目維護者知道他的功能已經能夠Review
了。
在這個工做流,Pull Request
的通知功能很是有用,
由於項目維護者不可能知道其它開發者在他們本身的倉庫添加了提交。
因爲各個開發有本身的公開倉庫,Pull Request
的源倉庫和目標倉庫不是同一個。
源倉庫是開發者的公開倉庫,源分支是包含了修改的分支。
若是開發者要合併修改到正式代碼庫中,那麼目標倉庫是正式倉庫,目標分支是master
分支。
Pull Request
也能夠用於正式項目以外的其它開發者之間的協做。
好比,若是一個開發者和一個團隊成員一塊兒開發一個功能,他們能夠發起一個Pull Request
,
用團隊成員的Bitbucket
倉庫做爲目標,而不是正式項目的倉庫。
而後使用相同的功能分支做爲源和目標分支。
2個開發者之間能夠在Pull Request
中討論和開發功能。
完成開發後,他們能夠發起另外一個Pull Request
,請求合併功能到正式的master
分支。
在Forking
工做流中,這樣的靈活性讓Pull Request
成爲一個強有力的協做工具。
下面的示例演示了Pull Request
如何在在Forking
工做流中使用。
也一樣適用於小團隊的開發協做和第三方開發者向開源項目的貢獻。
在示例中,小紅是個開發,小明是項目維護者。他們各自有一個公開的Bitbucket
倉庫,而小明的倉庫包含了正式工程。
fork
正式項目小紅先要fork
小明的Bitbucket
倉庫,開始項目的開發。她登錄Bitbucket
,瀏覽到小明的倉庫頁面,
點Fork
按鈕。
而後爲fork
出來的倉庫填寫名字和描述,這樣小紅就有了服務端的項目拷貝了。
Bitbucket
倉庫下一步,小紅克隆本身剛纔fork
出來的Bitbucket
倉庫,以在本機上準備出工做拷貝。命令以下:
git clone https://user@bitbucket.org/user/repo.git
請記住,git clone
會自動建立origin
遠程別名,是指向小紅fork
出來的倉庫。
在開始改代碼前,小紅要爲新功能先新建一個新分支。她會用這個分支做爲Pull Request
的源分支。
git checkout -b some-feature # 編輯代碼 git commit -a -m "Add first draft of some feature"
在新功能分支上,小紅按須要添加提交。甚至若是小紅以爲功能分支上的提交歷史太亂了,她能夠用交互式rebase
來刪除或壓制提交。
對於大型項目,整理功能分支的歷史可讓項目維護者更容易看出在Pull Request
中作了什麼內容。
push
功能到她的Bitbucket
倉庫中小紅完成了功能後,push
功能到她本身的Bitbucket
倉庫中(不是正式倉庫),用下面簡單的命令:
git push origin some-branch
這時她的變動可讓項目維護者看到了(或者任何想要看的協做者)。
Pull Request
Bitbucket
上有了她的功能分支後,小紅能夠用她的Bitbucket
帳號瀏覽到她的fork
出來的倉庫頁面,
點右上角的【Pull Request
】按鈕,發起一個Pull Request
。
彈出的表單自動設置小紅的倉庫爲源倉庫,詢問小紅以指定源分支、目標倉庫和目標分支。
小紅想要合併功能到正式倉庫,因此源分支是她的功能分支,目標倉庫是小明的公開倉庫,
而目標分支是master
分支。另外,小紅須要提供Pull Request
的標題和描述信息。
若是須要小明之外的人審覈批准代碼,她能夠把這些人填在【Reviewers】文本框中。
建立好了Pull Request
,通知會經過Bitbucket
系統消息或郵件(可選)發給小明。
Pull Request
在小明的Bitbucket
倉庫頁面的【Pull Request
】Tab能夠看到全部人發起的Pull Request
。
點擊小紅的Pull Request
會顯示出Pull Request
的描述、功能的提交歷史和每一個變動的差別(diff
)。
若是小明想要合併到項目中,只要點一下【Merge
】按鈕,就能夠贊成Pull Request
併合併到master
分支。
但若是像這個示例中同樣小明發現了在小紅的代碼中的一個小Bug
,要小紅在合併前修復。
小明能夠在整個Pull Request
上加上評註,或是選擇歷史中的某個提交加上評註。
若是小紅對反饋有任何疑問,能夠在Pull Request
中響應,把Pull Request
看成是她功能討論的論壇。
小紅在她的功能分支新加提交以解決代碼問題,並push
到她的Bitbucket
倉庫中,就像前一輪中的作法同樣。
這些提交會進入的Pull Request
,小明在原來的評註旁邊能夠再次review
變動。
Pull Request
最終,小明接受變動,合併功能分支到Master
分支,並關閉Pull Request
。
至此,功能集成到項目中,其它的項目開發者能夠用標準的git pull
命令pull
這些變動到本身的本地倉庫中。
到了這裏,你應該有了全部須要的工具來集成Pull Request
到你本身的工做流。
請記住,Pull Request
並非爲了替代任何 基於
Git的協做工做流
,
而是它們的一個便利的補充,讓團隊成員間的協做更輕鬆方便。
在看這部分前,請先回顧閱讀業界承認的成功的 Git Branch Work Flow 模型 A Successful Git Branching Model ,瞭解平常開發中的場景,有助於熟悉下面的使用過程。
在企業開發中,使用 Git 做爲版本控制軟件最看重的仍是結合公司本身搭建的 Gitlab,將 Code Review 加入打包部署持續集成的流程中,這樣,代碼開發完成,提交測試前,即可以對開發人員提交的代碼進行 Review,發現潛在的問題,及時指導,對於新人來說,也能更快更好的學習。
解決的需求場景以下:
上圖就是 xirong 團隊在平常開發中總結出來的適合企業開發的模式,下面進行簡單的介紹,方便你們學習瞭解,歡迎提交 Issue 進行討論。(本模式適合敏捷開發流程,小迭代上線,傳統的瀑布開發模型並無進行測試)
git merge --no-ff origin/master
,使得 Master 分支上的變動更新到迭代開發分支dev上面,以後,在 Gitlab 上面發起 pull request
請求,並指定 Code Review 人,請求的分支選擇本次上線的 release 分支,即 release20150730。這樣通過上面的1-5步驟,企業平常迭代開發中的代碼版本控制基本上就 Ok 了,有問題歡迎 Issue 討論。
2016-11月 更新 Git 分支開發部署模型 的一些使用原則以下:
Git-Develop 分支模式是基於 Git 代碼庫設計的一種須要嚴格控制發佈質量和發佈節奏的開發模式。develop 做爲固定的持續集成和發佈分支,而且分支上的代碼必須通過 CodeReview 後才能夠提交到 Develop 分支。它的基本流程以下: