版本控制
版本控制 (vcs) version control system
1. 版本控制是什麼
記錄一個或多個檔案的變化, 以便將來查閱特定版本的內容
2. 為什麼使用版本控制
記錄, 怕丟失
多人協同開發
歷史, 可以清楚的知道哪個時間點做了些什麼
3. 發展
-
本地版本控制
- 基於檔案差異
- 個人開發
- diff, patch
-
集中式版本控制 eg. svn
- 基於檔案差異
- 遠端庫, 不存在本地庫
- 多人開發
- 單點故障
-
分散式版本控制 eg. git
- 基於檔案快照
- 本地庫與遠端庫
- 多人並行開發 (完全並行), 環境隔離
- 安全, 可斷網開發
4. git 與 svn 的區別
-
版本控制設計思路
svn 等集中式的版本控制管理, 都是基於檔案差異來進行版本控制
- 每個版本均記錄哪些檔案有了更新, 以及更新了哪些行的哪些內容
git 是基於檔案快照的版本控制
- 每個版本並不記錄資料的差異, 而是比對檔案的指紋資訊並對檔案做快照, 然後儲存一個指向該快照的索引, 為了保證效能, 對於沒有變化的檔案, 不會再次儲存新快照, 而是對原快照做一個連結
e.g: 記錄人生成長的照片
由此可見, git 版本控制的設計有別於傳統的版本控制思路
-
本地庫與遠端庫 (local, origin)
svn 僅有集中式的遠端庫, 提交更新等幾乎所有操作均需要網路
git 除了有遠端庫之外, 本地庫也保留著和遠端庫一樣的資訊, 幾乎所有操作均不需要網路即可操作, 比如檢視修改歷史
e.g: 意味著, 我們可以在坐飛機或者火車的時候, 也可以進行愉快的開發工作, 看起來區別不大, 實際體驗過後, 你會驚喜的發現有很大的不同
-
工作區域的不同
svn 為 本地工作區域, 遠端庫
git 為 本地工作區域, 暫存區, 本地庫, 遠端庫
e.g: 寫多個紙張的作文 1. svn 方式: 統一把幾張紙寫完, 然後直接發給老師 2. git 方式: 寫完一張, 放到一旁, 直到最終寫完後, 統一發給老師 由此, git 引申出來檔案的三個狀態: 此處不再囉嗦了, committed, staged, modified
5. git 的強大之處 (分支)
- 分支的意義
幾乎每一種版本控制系統都以某種形式支援分支功能, 使用分支意味著每個人的開發工作都與主線以及其他人分離隔離開來, 互不影響的進行工作
- 分支是 git 的 "必殺技"
很多版本控制系統中, 建立分支, 切換分支是一個昂貴的過程, 他們的實現方式往往是源目錄的拷貝, 而 git 的建立分支以及分支切換幾乎可以在瞬間完成, 無論專案大小均是如此, git 的出現, 改變了程式員的開發方式
-
分支的實現方式 (內容定址)
-
上面說過, git 的版本控制對於每次提交都是以快照方式實現的, 而不是比較檔案差異, 那麼快照如何理解?
從圖可以看到, 我們的每次提交都會生成一個SHA-1演算法生成的字串(姑且叫做索引), 所有的這類字串可以理解為一個索引, 指向具體的資料物件, 可以看到提交物件中層層儲存著更多的索引, 通過索引一步步的找到所對應的實際內容, tree 可以理解為目錄
-
提交之間的上下級關係 (通過 parent)
-
分支的本質 (指向提交物件的可變指標)
分支其實就是從對應的提交物件追溯內容的過程
-
建立分支的過程, 其實就是在對應提交上新建一個指標指向該提交物件
-
git 會有一個當前所在指標 (名為 HEAD指標), 用來標識當前所在的分支
-
所以, 綜上所述, 大家明白了為什麼 git 的分支建立和切換的代價非常廉價了吧, 甚至可以一個專案同時進行幾千個分支的開發都沒有任何影響, 因為代價僅僅是建立指標(索引)而已, git 的分支建立以及切換和專案大小以及複雜度無關
-
-
分支的合併 (merge)
-
接到需求後, 基於 master 建立一個分支 iss53
-
完成了部分功能, iss53 進行了一次提交
-
此時, 功能還沒開發完, 但是突然線上有問題需要解決, 此時基於 master 建立 hotfix 分支, 並修改 bug 進行提交
-
當 hotfix 分支測試完後, 要合併到 master 上線
-
回到未完成功能的分支 iss53 繼續完成開發工作 (此分支完全不受任何影響)
-
此時 iss53 任務已完成, 需要合併 master 程式碼並上線
此 merge 操作會將 master 與 iss53 分支的末端 c4, c5 以及他們的共同祖先 c2 進行三方比較合併
-
合併上線之後
-
同 merge 類似的有個概念是 rebase 變基, 就先不在這裡說了, 初學者對於變基的概念不清楚很容易出現問題, 後面有機會在說
-
6. 工作當中的一些經驗
-
接到任務時, 第一時間要做的是切換到 master 分支, 建立一個新分支
git checkout master git fetch git pull git checkout -b liaoxing_xxx
-
程式碼開發到某階段想要儲存的時候
git add . // 當存在一些新建的未放入版本控制中的檔案以及目錄的時候使用 git commit -am "xxx" git push -u origin liaoxing_xxx // 推送到遠端並跟蹤
-
功能開發完畢後, 提測
// 先切換到 master 分支拉取最新程式碼 git checkout master git fetch git pull // 切換回開發分支, 合併 master 最新程式碼 git checkout liaoxing_xxx git merge master git commit -am "merge master" git push -u origin liaoxing_xxx // 切換到 develop 分支 git checkout develop git fetch git pull git merge liaoxing_xxx
-
測試完畢後, 上線
// 切換到 master, 獲取最新程式碼 git checkout master git fetch git pull // 切換到開發分支, 合併 master 最新程式碼 git checkout liaoxing_xxx git merge master git commit -am "merge master" git push -u origin liaoxing_xxx // 切換到 master 分支, 合併程式碼 git checkout master git merge liaoxing_xxx
-
上面的命令看著很多, 只是為了保證百分之百不出錯而已, 簡單來說, 有如下經驗
- 每次切換分支的時候, 都可以 git fetch, git pull 獲取一下最新程式碼
- 經常要和 master 程式碼對齊