隨著我們的 Python 專案越加複雜,我們應該開始考慮版本管理(version control)的問題。而現在最為人知的版本管理方法就是使用 Git。
為什麼需要版本管理?
版本管理(version control)為我們解決了數個非常重要的編程問題。以下我們略談一些重要性:
方便測試新功能
相信我們在編程的時候都會試過這個狀況:
我們更改了一些代碼後,發現新的代碼不能用,需要還原(Rollback)這些改變。
如果這些更改是簡單的,那麼可能使用 Ctrl + Z 已經可以還原代碼。但如果我們的更改牽涉數個檔案,那麼只用 Ctrl + Z 就不能快捷和準確地還原更改了。
版本管理就像是我們為每一個檔案拍了照、留了紀錄一樣,我們可以透過翻查相簿裡的舊照,輕鬆地還原檔案原來的面貌。
方便部署專案
與上一點相關的另一個狀況是:
我們在更改代碼,但部署(deploy)專案時,我們不想把這些最新、尚未經過多重測試的代碼部署到我們的環境(Production Environment)。
固然,我們希望在部署(deploy)途中仍可以修改我們的專案;但另一方面,我們也希望我們部署的代碼是穩定的。
版本管理讓我們可以輕易定義不同的「代碼版本」,讓我們可以選擇部署一個較為穩定的版本(Production version),又同時可以繼續研發新的功能。
方便與其他編程師合作
最後一個常見的狀況是:
我們想將代碼與其他編程師分享,但我們需要同時更改專案,甚至是同一個檔案。
如果我們想與其他人共享專案,那麼我們必須要找到一個方法確保我們的更改不會與其他編程師的更改重疊或起衝突。
版本管理讓我們可以有條不紊地與其他編程師合作,處理這些有可能是重疊的更改。
Git 的基本概念與用途
了解到為什麼版本管理這麼重要以後,我們一起來看看如何透過 Git 來解決這些難題。
什麼是 Git/GitHub
Git 其實是一個開放元代碼(open source)的軟體。
這個軟體是其中一個實行版本管理(version control)的軟體,間亦有其他可以實行版本管理的軟體,例如 SVN(Apache Subversion)、CVS(Concurrent Versions System)等。可是,論知名度及普及性,Git 還是略勝一籌,也有其獨當一面的功能,使它成為最為廣泛使用的版本管理軟體。
順帶一提,您或許會聽說過 GitHub 這個網站。其實 GitHub 是 Git 的其中一個實行(implementation),現在是微軟(Microsoft)旗下的一個產品。由於它提供慷慨的免費使用額度,許多編程師會選用 GitHub 為版本管理的方案(solution)。
以下我們簡介一下一些重要的 Git 概念,也可以應用在 GitHub 上。
Git 概念 1:修改(commits)、分支(branches)與主幹(master)
我們首先用一個非常簡單的例子講解 Git 最重要的 2 個概念:修改(commits)與分支(branches)。
我們可以想像修改(commits)是樓層,而分支(branches)是大樓。就像樓層是大樓的基本組成部分(building blocks),修改就是分支的基本組成部分。
修改(commits)就是檔案的一個剪影(snapshot)。每當我們完成一些對編程檔案的修改,例如在以上 Main.py,我們每次修改檔案以後,我們便可以增加一個新的修改(commit),紀錄這一個版本的檔案的更改。
而分支(branches)就是紀錄這些修改歷史(commits history)的骨幹。每一個分支(branch)都把修改(commits)按時序排列,而不同的分支可以有不同的修改(commits)。上圖的分支就是「master」。
這裡我們談談 2 個特別的名稱:
- master(主幹):這是每一個專案最重要的分支(branch),儲存了我們認為最重要的修改(commits),也是我們專案的權威性版本(authoritative version)。
- HEAD(主幹頭):這是主幹(master 分支)上最新的修改(commit)
現在您能理解為什麼 Git 的圖像是一個分支吧!
Git 概念 2:其他的分支(branches)
如我們上面提及,不同的分支(branches)可以有不同的修改(commits)。這就是所謂的分支化(branching)過程。
比方說,我們定義了一個名為「branch-A」的分支。這個分支與主幹(master)的分別在於它增加了一個名為「Commit-A1」的修改。這個修改比起主幹頭(HEAD)加入了 1 行的代碼。
我們可以稱「branch-A」為主幹上的分支(branch off master)。您能想像為什麼我們要這樣做嗎?
沒錯,有時我們希望測試一些新的功能,但我們未必希望立刻把這些新的功能融入到這個專案裡(可能我們需要多些測試等)。這時候,我們便可以把這些的更改成立一個新的修改(commit),但把這個修改儲存到一個並非主幹(master)的分支。
除了在主幹(master)上分支以外,我們也可以在分支上加入分支(branch off branch)!就如我們上面定義的「branch-A1」,其實就是在「branch-A」上延伸的一個分支。而「branch-A1」上有多一個修改「Commit-A1-1」,比起在「branch-A」上的「Commit-A1」又多加了 1 行代碼。
這裡我們經常會使用一個量度分支的方法,就是比較分支(branch)與主幹(master)有多少修改(Commit)的差別。以上圖為例,我們會說「branch-A」比主幹多出 1 個修改(1 commit ahead of master),而「branch-A1」比主幹多出 2 個修改(2 commit ahead of master)。
這讓我們可以大概了解到底這個分支與主幹有多少差別。
Git 概念 3:合併(merge)
了解到什麼是分支後,我們便可以理解什麼是合併(merge)了。
試想像我們現在滿意「branch-A」的更改(即是 Commit-A1 的內容),希望把這些修改加入到我們的主幹(master)版本。這時,我們便可以透過合併(merge)來完成這個動作。
合併就是一個把不同分支(branches)融合的過程。上文提及,由於不同分支的分別在於它們有不同的修改(commits),因此換句話說,合併就是把修改同步(sync)的過程。
以上圖為例,我們希望把「branch-A」合併到主幹(master)裡(merging Branch-A into master)。完成了這個動作後,我們的主幹便會加入了「Commit-A1」的修改,而「Commit-A1」便會成為新的主幹頭(HEAD)。
換個角度來說,我們其實把主幹(master)從原來的分支換成了「branch-A」。為什麼?試留意「branch-A」與新的主幹(master)其實有同樣的修改(commits)。
在 GitHub 裡,我們會見到一些名為「Pull Request」(或稱 Merge Request)的東西。這些其實就是所謂的「合併申請」,用於管理合併的動作。
結語
以上我們探討了一些版本管理和 Git 的概念。下一篇,我們一起來看看如何實踐這些概念,在我們的 VS Code 專案裡開始使用 GIt 吧!
下一篇:Git 2/4: 在 VS Code 啟用 Git?介紹 Git 版面基本操作
其他文章: