基於Git的主幹開發工做流

1、 SVN 與 Git 對比

首先,SVN 是一個集中式的版本控制系統,Git 是一個分佈式的版本控制系統,這是目前兩者最大的區別之一。
html

如上圖所示:對於不少操做來講,SVN必須在聯網下進行,而Git則在本地進行便可。但SVN有基於目錄級別的權限管理,而Git則須要藉助gitlab實現細粒度的權限管理。
前端

1.1 分支

SVN: SVN的分支僅僅是一些有特殊含義的目錄。在建立一個新的分支時,你只是把項目的當前狀態完完整整地拷貝到這個新的分支目錄中,建立完分支後,影響所有成員,每一個人都會擁有這個分支。
Git: Git的分支技術是它的設計核心,所以它擁有一個徹底不一樣的概念。一個在 Git 中的分支就是一個指向某次所提交版本的指針( commit 對象的可變指針):不拷貝任何文件,不建立任何目錄,沒有任何額外的操做。 在 Git 中你當前永遠工做在一個分支上,至少工做在那個系統默認建立的「master」分支上。在你的工做副本上只包括你當前的活動分支中的文件( Git稱之爲「HEAD」)。全部其餘的版本和分支都被保存在你的本地倉庫中,而且隨時均可以很是快速地恢復到一箇舊的版本。必定要記住 Git 的分佈式特性,分支能夠被髮布到在遠程服務器上,可是本地上的分支對於平常的工做更加劇要,git本身本地建立的分支不會影響其餘人。git

1.2 提交

SVN: 當你想要在 SVN 中提交一個改動,有以下的一些規則: 你必須確保與中央倉庫的鏈接。你不能進行離線提交。 提交的內容要當即存儲在中央倉庫中。 它會被分配一個全局遞增版本號。SVN具備一個很是重要的特性就是它的信息從不丟失,即便當你刪除了文件或目錄,它也許從最新版本中消失了 ,但這個對象依然存在於歷史的早期版本中。
Git: 提交在 Git 中就是徹底另一種狀況: 你沒有必要鏈接到任何一個 「中央」 倉庫,由於在你的計算機中就擁有一個完整的本地倉庫。所以提交僅僅只記錄在本地倉庫上。它們不會自動地傳遞到遠程倉庫中,除非你本身決定共享這個改動。 文件的改動並不意味着它會被自動地包含在下一次提交中。你必須指明哪些改動你想要提交,並把它添加的所謂的 「暫存區(Staging Area)」中。你甚至能夠只對文件的部分修改或是特定的幾行代碼進行提交,而其餘部分則稍後提交。「commit hashes」 替代了版本號碼。因爲提交都發生在開發人員的本地計算機上,你不可能給某個提交分配一個號碼 #5,而另一個分配 #6,這就產生了個問題,在分佈式系統下誰是第一個提交呢?在 Git 中,每個提交必須擁有一個惟一的ID,所以一個哈希字符串就代替了那個依次遞增的版本號。Git能夠丟棄最新的一個或幾個提交,使用 git reset –hard命令能夠永遠丟棄最新的一個或者幾個提交。Commit History 歷史記錄,存儲着全部提交的版本快照,並由當前分支引用的指針HEAD指向該分支最新一條提交。Git沒有一個全局版本號,而SVN有:目前爲止這是跟SVN相比Git比較明顯的區別。而且經過使用git rebase命令代替git merge命令操做,能夠更好的保持整潔的線性提交記錄。github

1.3 分享工做

SVN: 在 SVN 中,在提交以後,你的工做會被自動地轉移到中央倉庫上去。只有在你鏈接到這個中央服務器時你才能夠進行提交。
Git: Git 不會自動上傳任何東西。你能夠本身決定你的哪些分支須要共享給你其餘的團隊成員。除此以外共享工做也是十分安全的。衝突只會出如今你的本地上,它決不可能發生在遠程服務器上。這會讓你有信心來解決衝突,由於你不會破壞遠程倉庫。
數據庫

更多詳細區別請參考:
1. Git與SVN對比
2. Git與SVN對比
3. Git與SVN對比
segmentfault

2、 Git核心概念及操做

2.1 Git對象

Git 的核心部分是一個簡單的鍵值對數據庫, 你能夠向該數據庫插入任意類型的內容。你能夠在 .git/objects 目錄下看到一些文件,這就是Git 存儲內容的方式——一個文件對應一條內容。每次咱們運行 git add 和 git commit 命令時, Git 所作的實質工做——將被改寫的文件保存爲數據對象,更新暫存區,記錄樹對象,最後建立一個指明瞭頂層樹對象和父提交的提交對象。 這三種主要的 Git 對象——數據對象樹對象提交對象——最初均以單獨文件的形式保存在 .git/objects 目錄下。 緩存

2.2 工做區域

以下圖所示:Git工做區域分爲三部分,工做目錄(Working Directery)暫存區(Staging Area)Git倉庫( Repository) 安全

工做目錄(Working Directery): 是電腦中實際的目錄,通常是從Git倉庫壓縮數據當前版本中解壓出來的文件列表。因此你在本地磁盤看到的你項目源碼的文件列表,其實就是Git開放給你的一個沙盒。在你將文件的修改添加到暫存區域並將快照記錄到提交歷史(本地倉庫)以前,你能夠隨意更改。可經過git add(可屢次)將修改添加到暫存區以準備一塊兒commit到本地倉庫 ,也能夠直接經過 git commit -a 選項,Git 就會自動把全部已經跟蹤過的文件暫存起來一併提交,從而跳過手動git add 的步驟。
暫存區(Staging Area): 相似於緩存區域,它是一個文件臨時保存你的改動,保存着即將提交的文件列表快照。可經過git commit將全部緩存區的內容提交到本地倉庫。
倉庫(Repository): 分爲本地倉庫和遠程倉庫,本地倉庫等待合適的時機(功能完成/提交補丁/持續集成功能),經過git push 將本地倉庫代碼的變化同步更新到對應的線上代碼倉庫(遠程倉庫)以供別人或其餘分支經過git pull拉取合併。

2.3 Git操做

以上幾塊區域間的數據流動操做大體以下圖所示,更多操做命令請查閱 git文檔服務器

暫存相關操做
將(文件)修改添加到暫存區: git add fileName.xx 或 git add --all(全部文件)
查看暫存區文件列表: git ls-files --stage
查看暫存區文件內容: git cat-file -p f48r4s(指向文件的哈希值指針)
對比工做目錄與暫存區(文件): git diff [fileName.xx](省略則對比全部)
撤銷暫存區的(文件)修改: git reset HEAD fileName.xx 或 git reset .(全部文件)

提交相關操做
將暫存區內容提交到本地庫: git commit [fileName.xx](省略則提交全部) [-m '這裏能夠寫提交信息']
查看本地提交記錄: git log
查看某次本地提交內容: git show [commitId](不填則顯示最新提交內容) [fileName.xx](指定提交的指定文件內容)
撤銷/回滾某次提交: blog.csdn.net/qq_33442844…

分支相關操做
切換分支: git branch xxx(分支名)
新建並切換分支: git branch -b xxx(分支名)
設置默認追蹤的遠程分支: git branch --set-upstream-to=origin/remoteBranchName(遠程分支名) [localBranchName](省略則默認爲當前本地分支)
設置默認推送的遠程分支: www.cnblogs.com/x_wukong/p/…

查看分支相關操做
查看本地分支: git branch
查看遠程分支: git branch -r
查看全部分支: git branch -a
查看本地與遠程分支對應關係: git branch -vv

另外,可使用git stash命令將本地分支上工做目錄(的已追蹤文件)的修改與暫存區的內容轉移隱藏起來,而後等合適的時機經過git stash pop將隱藏內容轉移過來,隱藏的內容可在分支間共享。(使用場景是:開發中到緊急bug fix須要將工做內容保存起來,或本地分支間的代碼轉移等等)。

2.4 文件狀態

常見操做下的文件狀態轉換以下圖所示: 負載均衡

未追蹤(untracked): 表示文件存在在工做目錄中,但未添加到Git中去參與文件版本管理。
未修改(unmodified): 表示文件已在Git版本管理中,工做目錄的文件與版本庫相比沒有任何改動。
已修改(modified):表示在工做目錄下修改了文件;工做目錄是對項目的某個版本獨立提取出來的內容,放在磁盤上供你使用或修改,可是還沒暫存到暫存區或提交到本地代碼庫中。
已暫存(staged): 表示對已修改文件的當前版本作了標記,存放在一個不可見的暫存區域(可經過git ls-files命令查看),作爲下次提交的內容的一部分。其實暫存區域是一個文件,保存了下次將提交的文件列表信息,有時候也被稱做索引。
已提交(committed): 表示數據已經永久的保存在本地Git版本庫中。

2.5 文件對比

不一樣工做區域之間的文件對比,可使用git diff命令,以下圖所示:

git diff: 查看還沒有暫存的文件更新了哪些部分。
git diff --cached: 查看已暫存文件和上次提交時的快照之間的差別。
git diff HEAD: 查看未暫存文件與最新提交文件快照的區別。
git diff commitId01 commitId02: 查看不一樣提交快照之間的區別。
git diff origin/xxx: 本地全部地方與遠程分支對比。

更多概念及操做詳見:
1. Git詳細教程
2. Git詳細教程
3. Git詳細教程
4. Git詳細教程
5. Git概念及操做原理

3、 Git工做流之:主幹開發

使用主幹開發後,咱們的遠程代碼庫原則上就只能有一個 Master 分支了,但本地能夠隨意建立多個分支供本身使用(好比能夠專門基於本地主要開發分支建立一個分支用來作沒有把握的嘗試性的實驗性的開發,由於當正確的代碼與嘗試性的代碼混合起來時要剔除這些錯誤的嘗試性代碼如同合併兩個長久未合併的分支同樣是很是麻煩的,因此當嘗試性的開發失敗時,直接丟棄這個分支是很方便的,若嘗試成功,則能夠在本地merge回本身的本地主要開發分支),全部新功能的提交也都提交到 Master 分支上,沒有了分支的代碼隔離,測試和解決衝突都變得簡單,持續集成也變得穩定了許多,問題也接踵而至,主要有如下四個:

  1. 如何避免發佈的時候引入未完成的 Feature
  2. 如何進行線上 Bug Fix
  3. 如何重構
  4. 如何解決衝突

3.1 如何避免發佈引入未完成 Feature

答案是: Feature Toggle。
既然代碼要隨時保持可發佈,而咱們又須要只有一份代碼來支持持續集成,在代碼庫里加一個特性開關來隨時打開和關閉新特性是最容易想到的也是最容易被質疑的解決方案。 Feature Toggle 是有成本的,不論是在加 Toggle 的時候的代碼設計,仍是在移除 Toggle 時的人力成本和風險,都是須要和它帶來的價值進行衡量的。事實上,在咱們作一個前端的大特性變動的時候,咱們確實沒有由於沒辦法 Toggle 而採用了一個獨立的 Feature 分支,咱們認爲即便爲了這個分支單獨作一套 Pipeline,也比在前端的各類樣式間添加移除 Toggle 來得簡單。但同時,團隊應該約定在每次提交前都要先將 Master 分支 Merge 到 Feature 分支,以此避免分支隔離久之後合併時的痛苦。

3.2 如何進行線上 Bug Fix

在發佈時打上 Release Tag,一旦發現這個版本有問題,若是這個時候Master分支上沒有其餘提交,能夠直接在 Master 分支上 Hot Fix,若是 Master 分支已經有了提交就要作如下幾件事:

從 Release Tag 建立發佈分支。
在 Master 上作 Fix Bug 提交。
將 Fix Bug 提交 Cherry Pick 到 Release 分支。
在Release 分支再作一次發佈。

之因此不在 Release 分支直接 Fix,再合併到 Master 分支這樣作,是爲了防止bug fix後忘記merge回Master分支。

3.3 如何重構

這裏指的是比較大規模的重構,沒法在一次提交完成,TBD 要求每一次提交都是一個可上線的版本,因此這同時還意味着這個重構沒法再一個上線週期內完成。 這種狀況,須要在代碼設計中增長一個抽象層,保證在重構過程當中先不動原來的代碼,也不破壞既有功能,相似於藍綠部署中的負載均衡器的做用,這樣的流程就是:

在將要被重構的代碼邏輯附近引入抽象層而後提交,對全部人可見。若是有須要能夠是多個提交,這些提交都不能破壞 build,而後依次 push 到共享代碼庫。
爲將要被引入的代碼寫抽象層的第二次實現,而後提交。但在主幹上因爲關閉狀態因此其餘開發人員暫時不依賴於它。若是須要的話,這可能像上面那樣須要屢次提交。第一步的抽象層也可能偶然被調整,但必須遵循一樣的原則:
不能破壞build。
切換使用重構後的代碼,而後 Push。
刪除原有的舊實現(被重構代碼)
刪除抽象層




主幹開發參考文章鏈接:
1.主幹開發
2.功能開關
3.功能開關
4.分支模型與主幹開發
相關文章
相關標籤/搜索