Git 作為主流的版本控制系統,其分散式架構和高效能使其在軟體開發中扮演著關鍵角色。相較於集中式架構,Git 的本地倉函式庫機制允許開發者離線工作,避免了單點故障和網路依賴的風險。其分支模型能有效支援平行開發,簡化團隊協作流程並提升開發效率。雖然 Git 命令列介面具有一定的學習曲線,但掌握核心指令如 init、add、commit、status 和 log 等,即可完成大部分日常操作。此外,瞭解如何排除不必要檔案(例如編譯產物、大型檔案和敏感資訊)對於維護倉函式庫的乾淨和安全至關重要。透過妥善設定 .gitignore 檔案,可以避免將這些檔案提交到版本控制系統中,減少儲存空間的浪費並提升協作效率。對於初學者而言,理解 Git 的基本概念和工作流程是入門的關鍵,而持續的練習和探索則能進一步提升 Git 的使用技巧。
為何使用 Git?
Git 是目前最受歡迎的版本控制系統 (Version Control System, VCS),其主要優點在於能夠促進安全且快速的開發流程。Git 允許開發者使用分支來進行多重平行開發,這使得開發過程更加靈活且高效。
快速
Git 的操作速度極快。無論是新增檔案、提交變更、還原舊版本還是同步檔案以整契約事的修改,這些操作都能在短短幾秒內完成,即使是大型專案也不例外。特別是建立、使用及合併分支這些操作,Git 的速度極其迅速,這也是許多開發者熱愛使用 Git 的主要原因之一。
可靠性
可靠性應該是任何 VCS 的基本要求:如果系統丟失檔案或修改,那麼它將無法正常運作。然而,許多歷史上的 VCS 並不完全可靠。在2000年代初期,有一個由一百多名開發者組成的團隊曾使用當時主流的專有 VCS,儘管這個工具被視為最佳選擇,但仍經常出現丟失或搞亂修改的情況。
相反地,Git 憑藉其嚴謹的設計和可靠性而聞名。當然,Git 是一個複雜的工具,如果不熟悉它的命令使用方式,可能會因為人為錯誤而導致資料丟失。但是,由於技術問題導致資料丟失的情況幾乎是聽聞未見的。Git 已經被全球無數團隊信任並廣泛使用,這種信任是完全值得的。
分散式架構
在 Git 出現之前,許多 VCS 使用的是集中式架構。這意味著要編輯一個檔案,你需要從中央伺服器取得其最新版本,進行修改後再提交回中央伺服器以供其他團隊成員存取。
集中式架構有幾個問題:
- 檔案鎖定:一些集中式 VCS 鎖定任何你已經簽出的檔案,以防止其他人在你編輯時修改它們。這會導致大量「你還在編輯 Foo.java 嗎?」這類別對話,造成不便和尷尬。
- 網路依賴:你需要與中央伺服器保持連線才能簽出或提交檔案。沒有網路連線時無法有效工作。
- 單點故障:如果中央伺服器故障或資料丟失,所有開發者都會停滯不前。
- 擴充套件性問題:隨著團隊擴充套件,集中式架構可能無法很好地滿足需求。
分散式架構如何解決這些問題?
Git 的分散式架構解決了上述所有問題。每個開發者在本地電腦上都擁有一整份專案副本,包括所有檔案、編輯歷史、標籤、提交資訊及其他後設資料。這意味著你可以在沒有網路連線的情況下進行工作。
此圖示
Git 的缺點
儘管 Git 有許多優點,但它也有一些缺點。Git 是由 Linus Torvalds 所設計的,因此它的命令列操作可能會顯得不一致、混亂且反直觀。舉例如下:
# git branch 命令不同用法示範
git branch # 列出所有分支
git branch foo # 建立名為 foo 的新分支
git branch --delete foo # 刪除名為 foo 的分支
你可能期望這些命令如下:
git branch --list # 列出所有分支(雖然 --list 也能工作但不常用)
git branch --create foo # 建立名為 foo 的新分支(不存在)
git branch --delete foo # 刪除名為 foo 的分支(存在)
然而實際上並非如此。因此,學習和記住不同命令和選項語法是必要的。這只是 Git 命令列操作的一小部分挑戰。
內容解密:
git branch命令用於管理分支。git branch不帶引數時會列出所有現有分支。git branch <branch-name>用於建立一個新分支。git branch --delete <branch-name>用於刪除指定分支。
學習 Git 的命令列工具需要一些時間和練習,因為它們的語法和選項可能不直觀。這也促使許多開發者使用圖形化介面或整合開發環境 (IDE) 外掛來簡化操作。
總結來說,儘管 Git 有其複雜性和學習曲線,但其高效、可靠和靈活性使其成為現代軟體開發中的不可或缺之工具。
Git 基礎操作
Git 是一個強大的版本控制系統,但其豐富的功能和組態選項可能讓初學者感到困惑。官方檔案《Pro Git》長達 511 頁,這讓人不禁懷疑是否需要掌握所有 Git 的概念和命令才能高效使用它。實際上,你只需學習一些常用命令和概念,就能完成 95% 的 Git 相關任務。這些命令透過反覆練習會逐漸內化,其他特定操作可以根據需要查詢。
存放程式碼以保持安全
要充分利用 Git 的優勢,首先需要知道如何將檔案新增到 Git 中。這裡首先介紹倉函式庫(repository)的概念。倉函式庫是 Git 用來存放專案檔案及其變更歷史的地方,類別似於銀行保險箱。
建立倉函式庫
有兩種主要方式來建立倉函式庫:
- 轉換普通目錄為 Git 倉函式庫:
- 在目錄內使用
git init命令即可轉換為 Git 倉函式庫。 - 使用
git status命令可以確認目錄已轉換為 Git 倉函式庫。
- 在目錄內使用
以下是建立名為 hats-for-cats 的新倉函式庫的步驟:
$ mkdir hats-for-cats
$ cd hats-for-cats
確認目錄尚未轉換為 Git 倉函式庫:
$ git status
fatal: not a git repository (or any of the parent directories): .git
使用 git init 命令轉換目錄為 Git 倉函式庫:
$ git init
再次檢查狀態:
$ git status
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
- 複製現有倉函式庫:
- 使用
git clone命令從他人的電腦上下載現有的 Git 倉函式庫副本。
- 使用
新增檔案到倉函式庫
現在,我們來向 hats-for-cats 專案中新增一個待辦事項清單。首先,使用 touch 命令或文字編輯器建立一個名為 todo.txt 的檔案:
$ touch todo.txt
此時,目錄中已經有了檔案,但 Git 尚未跟蹤該檔案。將檔案新增到 Git 中是一個兩步驟的過程:
- 將檔案移動到暫存區:
- 使用
git add命令將檔案移動到暫存區。
- 使用
$ git add todo.txt
- 提交暫存區中的所有檔案:
- 使用
git commit命令將暫存區中的檔案提交到倉函式庫。
- 使用
暫存區與提交
Git 的「快照」機制透過「暫存與提交」來實作。你可以控制何時進行快照以及每個快照中包含哪些檔案。例如,如果你正在編輯 foo.py 和 bar.py ,但只想現在快照 foo.py ,那麼只需將 foo.py 新增到暫存區並提交即可。
以下是處理不同檔案變更的四種情況:
- 建立新檔案。
- 編輯現有檔案內容。
- 重新命名或移動檔案(對於檔案系統而言,這些是同一操作)。
- 刪除檔案。
無論進行哪種操作,當你將一個或多個檔案新增到暫存區並提交時,都會生成包含該暫存區中所有檔案的新 Git 快照。
為什麼需要「暫存與提交」?
這樣設計的原因是讓你能夠在一次提交中包含多個檔案。例如,你可能會編輯一個原始碼檔案、相關測試程式碼和檔案檔案,這些變更都屬於同一次錯誤修復的一部分。你希望將這三個檔案包含在同一次提交中,因為它們之間存在邏輯關係。
問題解答
問:Git 是否能夠管理空白檔案? 答:是的,Git 能夠管理空白檔案。
問:如何確認目錄已轉換為 Git 倉函式庫?
答:使用 git status 命令可以確認目錄已轉換為 Git 倉函式庫。
問:如何檢視目前倉函式庫中的所有變更?
答:使用 git status 命令可以檢視目前倉函式庫中的所有變更。
問:如何將新建立的 todo.txt 檔案提交到倉函式庫?
答:首先使用 git add todo.txt 命令將檔案新增到暫存區,然後使用 git commit -m "Initial commit" 提交檔案。
基本 Git 指令練習
首先,我們可以使用 git commit 指令來提交變更。但在這之前,讓我們來聊聊提交訊息的重要性。
每次提交都需要一個人類可讀的提交訊息,這是由提交者提供的。最簡單的方式是將這個訊息作為引數傳遞給 git commit 指令,使用 --message 選項:
$ git commit --message "新增待辦事項清單"
如果你再次執行 git status,你會發現沒有任何檔案等待提交,這意味著你的待辦事項清單已經安全地儲存在倉函式庫中,所有未來對它的修改都將由 Git 追蹤。恭喜你,你剛剛完成了第一次 Git 操作!
現在,我們暫停一下,來看看 Git 在每次提交中包含哪些內容。你已經瞭解到一個提交包含了檔案的內容以及描述提交目地的訊息,但還有幾個其他資訊也被包含在內。以下是完整的列表:
- 檔案內容的任何變更(或檔名稱或檔案系統中的位置)。
- 一個 40 字元的十六進位數字串,稱為安全雜湊演算法(SHA),這是根據提交檔案的內容生成的字串。一個提交的 SHA 唯一標識該提交;可以把它想像成該提交的唯一名稱。SHA 是不連續的:每個 SHA 完全不同於前一個提交的 SHA。
- 提交者的名稱和電子郵件。
- 提交時間戳。
- 一個人類可讀的訊息描述為什麼進行這次提交。
- 指向分支上之前的提交(或父提交)的一個指標。我們將在下一節介紹分支的概念並進一步討論這個指標。
git log 指令會顯示當前分支上所有提交的這些資訊(我們稍後會更詳細地解釋分支)。假設你已經進行了兩次提交:一次是建立空的待辦事項清單,另一次是向該清單新增一項任務。執行 git log 會產生類別似以下的輸出:
$ git log
commit 7d4c98438ade780531e1baa283b3239c21943171 (HEAD -> master)
Author: George Spelvin <george.spelvin@example.com>
Date: Tue Jan 4 09:57:37 2022 -0800
add first item to list
commit 63ea581d1bc693dac159c146fa10d1cbfa4e6366
Author: George Spelvin <george.spelvin@example.com>
Date: Sun Jan 2 12:31:27 2022 -0800
add list of tasks to do
這些輸出包括你兩次提交的資訊,最新的一次顯示在頂部。你能找到每次提交的 SHA、作者資訊、時間戳和提交訊息嗎?如果你在自己的電腦上執行這些指令,你會看到每次提交不同的詳細資訊,但輸出格式將保持不變。
在這個例子中,所有提交資訊都是由你自己進行的。但這只是因為你是這個分支上唯一新增過提交的人。如果其他人也對同一分支進行了提交,你將會在輸出中看到他們的提交資訊。
排除檔案不納入倉函式庫
此時,你可能會認為將專案中所有檔案都納入暫存區並進行提交是明智之舉。然而,有幾種型別的檔案通常不希望儲存在 Git 或任何其他版本控制系統中。這些檔案包括但不限於以下幾種:
- 從其他檔案生成的檔案
- 極其龐大的檔案
- 包含秘密資訊的檔案
第一種型別包括從原始程式碼編譯而來的可執行檔案,或者從原始文字(例如 Markdown)生成 PDF 的過程中產生檔案。由於可以從原始檔案重新生成這些檔案,因此無需將它們儲存在 Git 中。此外,將它們儲存在 Git 中可能會導致漂移問題,即原始檔和生成檔案之間失去同步。例如,原始檔可能包含上週的程式碼,而編譯後的可執行檔案可能包含上個月的程式碼。這種情況可能會導致各種意想不到問題。
龐大檔案則帶來不同型別問題。如果增加了一個 5 GB 的 ISO 檔案或一個 10 GB 的資料集,那麼任何複製該專案倉函式庫到本地機器的人都必須下載該檔案。我們之前曾說過 Git 是快速的,但它無法處理擁擠或慢速網路問題。由於複製倉函式庫是 Git 使用者中相當常見操作之一,因此應避免將龐大檔案包含在專案倉函式庫中。通常更有意義的是將它們放置於 Git 外部分享驅動器或其他可存取資料儲存系統中。
每行程式碼解說
$ git commit --message "新增待辦事項清單"
此行指令用於建立一個新版本並同時附上描述性訊息「新增待辦事項清單」。如要深入瞭解此行指令背後邏輯以及如何使用及設定該指令請參考Git官方網站。
$ git log
此行指令用於列出本地倉函式庫中的所有Git提交記錄及其詳細資訊,例如SHA、作者資訊、時間戳以及訊息等。
排除指設定檔案
有些型別の檔案最好不要納入Git版本控制系統,包括:
* 編譯自其他檔案生成之檔案(例如:編譯後程式碼)
* 極大尺寸之檔案
* 包含機密資訊之檔案
排除流程解說
避免以上三種被排除檔案納入Git控制系統,可有效降低發生漂移問題機率,且避免系統遭受攻擊機率增加。
複製流程圖示
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Git 版本控制系統核心概念與應用實踐
package "Git 版本控制" {
package "工作區域" {
component [工作目錄
Working Directory] as work
component [暫存區
Staging Area] as stage
component [本地倉庫
Local Repository] as local
component [遠端倉庫
Remote Repository] as remote
}
package "基本操作" {
component [git add] as add
component [git commit] as commit
component [git push] as push
component [git pull] as pull
}
package "分支管理" {
component [git branch] as branch
component [git merge] as merge
component [git rebase] as rebase
}
}
work --> add : 加入暫存
add --> stage : 暫存變更
stage --> commit : 提交變更
commit --> local : 版本記錄
local --> push : 推送遠端
remote --> pull : 拉取更新
branch --> merge : 合併分支
note right of stage
git status 查看狀態
git diff 比較差異
end note
@enduml內容解密:
此圖示展示如何有效排除需要排除之檔案,以確保專案資料夾無多餘及需要被排除之檔案.
排除步驟:
1.首先確認專案內有沒有需要被排除之檔案?
2.若有則排除該檔案,並更新專案.
3.若確認專案資料夾無不必要之檔案則完成.
玄貓認為想要成為一名優秀程式設計師,必須掌握各種語言及技能,包括但不限於Python,Ruby及Go語言.