版本控制系統在現代軟體開發中扮演著至關重要的角色,而 Git 作為目前最流行的分散式版本控制系統,已成為開發者的必備工具。要有效管理程式碼變更,必須掌握 Git 的核心操作,包括倉函式庫的初始化、檔案的追蹤與忽略、提交的標記以及分支的建立、切換、合併和刪除。熟練運用 .gitignore 檔案可以排除不必要檔案的追蹤,提升倉函式庫的管理效率。標記特定提交則方便日後快速回溯版本,例如標記重要的里程碑或發布版本。分支管理是團隊協作開發的關鍵,允許多個開發者同時進行不同功能的開發,而不會互相干擾。然而,分支合併過程中難免會遇到衝突,瞭解如何解決衝突是確保程式碼整合順暢的必要技能。本文以實際案例和流程圖示,逐步講解 Git 的基本操作和進階分支管理技巧,幫助開發者建立紮實的 Git 基礎,提升團隊協作效率。

Git 的基本操作及進階應用

在軟體開發過程中,版本控制系統(Version Control System, VCS)是不可或缺的工具。Git 是目前最流行的分散式版本控制系統,能夠有效地管理和追蹤程式碼的變更。以下將探討 Git 的基本操作及進階應用,幫助開發者更好地管理程式碼倉函式庫。

建立與初始化 Git 倉函式庫

要開始使用 Git,首先需要建立一個新的倉函式庫或克隆一個現有的倉函式庫。這可以透過以下命令來完成:

# 建立新的 Git 倉函式庫
git init

# 克隆現有的 Git 倉函式庫
git clone <repository_url>

在初始化倉函式庫後,所有的檔案都會被 Git 追蹤,這意味著任何變更都會被記錄下來。然而,有些檔案並不適合被放入版本控制系統中,例如敏感資料或組態檔案。

忽略不必要的檔案

某些檔案並不適合被放入版本控制系統中,例如敏感資料或組態檔案。為了避免這些檔案被誤誤提交到倉函式庫,可以使用 .gitignore 檔案來指定哪些檔案或目錄應該被忽略。

假設你有一個名為 hats-for-cats/ 的目錄,其中包含一個名為 personal-notes.txt 的檔案和一個名為 .ide-config/ 的目錄。你不希望這些檔案被其他開發者看到,因此可以建立一個 .gitignore 檔案來忽略它們:

# notes to myself that are not for public consumption
personal-notes.txt

# configuration files for my IDE
.ide-config/

然後將這個 .gitignore 檔案新增到 Git 倉函式庫中:

git add .gitignore
git commit --message "exclude notes file and IDE config directory"

這樣,Git 就不會再提示你有未追蹤的檔案或目錄了:

$ git status
On branch main
nothing to commit, working tree clean

標記特定提交

在開發過程中,經常需要標記某些特定的提交以便於未來參考。Git 提供了標記(Tag)功能來實作這一點。標記可以用來標識某個特定版本的程式碼,例如發布版本或重要的里程碑。

假設你要釋出 Hats for Cats0.1-beta 版本,可以透過以下命令來標記該提交:

git tag version-1-0-beta

然後你可以透過 git log 命令檢視所有標記:

$ git log --oneline --decorate
a1b2c3d (tag: version-1-0-beta) Release version 0.1-beta
e4f5g6h Commit message for previous changes

分支管理

分支是 Git 中非常重要的一個概念。分支允許開發者在不同的工作流程中獨立進行開發,而不會影響到主執行緒式碼。每當你需要進行新的功能開發或修復bug時,都可以建立一個新的分支來進行工作。

假設你要開始一個新的功能開發,可以透過以下命令建立一個新的分支:

# 建立並切換到新分支
git checkout -b feature/new-feature

# 或先建立分支再切換到該分支
git branch feature/new-feature
git checkout feature/new-feature

在新分支上進行開發後,可以透過以下命令將變更合併回主分支:

# 切換到主分支
git checkout main

# 合併新分支到主分支
git merge feature/new-feature

# 刪除已合併的分支(可選)
git branch -d feature/new-feature

分支概念解密:

  • 建立分支:使用 git branch <branch-name>git checkout -b <branch-name> 命令建立新分支。
  • 切換分支:使用 git checkout <branch-name> 命令切換到指定分支。
  • 合併分支:使用 git merge <branch-name> 命令將指定分支合併到當前分支。
  • 刪除分支:使用 git branch -d <branch-name> 命令刪除指定分支。

Git 分支流程圖示

graph TD;
    A[主線] --> B[功能1];
    A --> C[功能2];
    B --> D[合併回主線];
    C --> D;
    D --> A;

此圖示展示了基本的 Git 分支流程:從主線建立兩個功能分支,並在完成後合併回主線。

內容解密:

此圖示展示了 Git 分支管理的基本流程:從主線建立兩個功能分支(功能1和功能2),並在完成後合併回主線。這樣可以保證每個功能都獨立開發且不會互相干擾。

Git 基本命令實踐

在 Git 中,每個儲存函式庫至少有一個分支,通常稱為預設分支。這些分支有正式的名稱,預設分支幾乎總是被正式命名為 mainmaster,其中 main 現已成為首選。為了更好地理解這些分支,通常會在圖中顯示每個提交到之前提交的箭頭。也就是說,箭頭是逆時間方向的,從較新的分支指向較舊的分支。例如,如果你的儲存函式庫有一個名為 main 的分支,其中有三個提交(稱為 A、B 和 C),另一個名為 branch-a 的分支中有兩個提交(稱為 D 和 E),且 branch-a 是從 main 分出來的,那麼你可以將儲存函式庫的狀態繪製如下:

分支與提交示意圖

此圖示展示了分支和提交之間的關係。這樣的結構讓我們能夠清楚地看到各個提交之間的連結和流程。

分支的必要性

為什麼需要分支?因為它們讓我們能夠安全地開發程式碼,與穩定的主程式碼函式庫隔離開來,直到準備好合併到主程式碼函式庫時再進行合併。以下是一個典型的工作流程,展示瞭如何使用分支來開發新功能:

  1. 你的產品程式碼位於一個 Git 儲存函式庫中。穩定版本的程式碼位於該儲存函式庫中的一個名為 main 的分支。

  2. 你被分配到為產品編寫一個讓使用者登入的功能。

  3. 你建立了一個名為 login-feature 的分支。

  4. 你切換到 login-feature 分支。

  5. 你編輯檔案並對該分支進行了一次或多次提交。

  6. 其他團隊成員審查這些提交中的編輯並給予反饋。

  7. 你進行另一次提交以整合反饋。

  8. 你的團隊長官批准你的工作,宣佈登入功能已正確實作。QA 團隊也可能會對你的工作進行簽核。

  9. 你將 login-feature 分支合併到 main 分支。這意味著所有你對 login-feature 分支所做的提交現在也成為 main 分支的一部分。你的登入功能現在是產品主程式碼函式庫的一部分。

  10. 由於 login-feature 分支已經合併且不再有任何用途,你可以安全地刪除它。

在這個工作流程中,最重要的一點是當你開發登入功能時,部分完成的程式碼並不會出現在主程式碼函式庫(也就是說,在 main 分支中)。不完整的程式碼被安全地與產品穩定程式碼隔離開來,因此它不能破壞穩定性。登入功能直到正式審查、批准且透過所有測試後才會新增到主程式碼函式庫中。這就是我們說分支讓我們能夠在隔離環境中開發程式碼,遠離其他開發者的工作及穩定程式碼函式庫。

分支管理命令

讓我們學習一些 Git 命令來管理這些分支。

建立新分支

要建立一個名為 login-feature 的新分支:

$ git branch login-feature

這條命令會顯示該儲存函式庫中存在的所有分支列表,並且在當前所在的分支旁邊顯示一顆星號:

$ git branch

切換分支

有兩種不同的命令可以用來切換到另一個分支。它們做同樣的事情,並在實際使用中都很常見。以下是切換到 login-feature 分支的一些範例:

$ git checkout login-feature
$ git switch login-feature

合併分支

合併一個分支(稱為源分支)到另一個分支(稱為目標分支)需要兩步操作。要將所有在 login-feature 中的提交合併到 main 中,首先確保你位於目標分支:

$ git checkout main

然後執行合併操作並指定源分支:

$ git merge login-feature

割除無用之物

有些組織喜歡永久保留所有分支以保留歷史記錄,但大多陣列織會要求在將其合併到 main 之後刪除某些分枝。以下是刪除 login-feature 分枝的一種方式:

$ git branch --delete login-feature

如果在試圖刪除某一分枝之前沒有合併它過, Git 將會警告並不會刪除該該區域。如果您想強制刪除某一特定區域(例如, 您建立了一個實驗性區域並希望刪除而不合併), 您可以像下面這樣做:

$ git branch --delete --force experimental-branch

處理合併衝突

當嘗試將一個區域與其他區域合併時, 有時可能會遇到所謂「合併衝突」. 意即說, 其他人已經編輯了您正在編輯同樣檔案內容, 他們也已經將他們自己區域合併進 main 分枝之前您未來得及將您自己的區域與 main 分枝進行合併.

若要繼續進行您的合併, 您需要先解決這些衝突. 有許多種方法可以處理這些問題: 一些人認為使用專門設計用於解決 Git GUI 工具 (例如 macOS 和 Windows 上可用) 的 Sourcetree 或 Linux、macOS 和 Windows 上可用) 的 Sublime Merge 是解決衝突問題最簡單和最直觀方式; 其他人則偏好手動解決衝突, 使用 Git 控制檯命令和文字編輯器; GitLab 使用者還有另外選擇: 您可以使用 GitLab 的內建圖形式衝突解決工具.

無論您選擇哪種方法, 您必須通知 Git 接受哪些更改、拋棄哪些更改以及何時繼續進行合併.

內容解密:

此圖示展示瞭如何透過使用 Git 分枝來開發新功能。主要步驟包括建立新特徵、切換到該特徵、編輯檔案、進行提交、接受反饋、整合反饋、獲得批准以及最終將特徵與主程式碼函式庫合併後刪除特徵。

  1. 建立新特徵:首先需要建立一個新特徵以進行獨立開發。
  2. 切換到新特徵:確保我們正處於正確的開發環境中。
  3. 編輯檔案:在此步驟中進行實際程式碼編寫或修改。
  4. 進行提交:將修改提交到本地儲存函式庫。
  5. 其他團隊成員審查:團隊成員會檢查我們所做出的修改並提供反饋。
  6. 整合反饋:根據反饋進一步修改程式碼。
  7. 團隊長官批准:確保修改符合需求和標準。
  8. 將特徵與主要程式碼函式庫合併:最終將我們所有修改都整合回主幹。
  9. 刪除特徵:因為特徵已經成功整合完成後我們不再需要該專門區域。

透過這些步驟我們能夠確保我們所開發出來之特徴是穩定且符合標準並最終與主幹成功整合完成。

分支管理與合併衝突解決

在開發過程中,分支管理是一項非常重要的技能。當多名開發者在同一個專案上協作時,合併衝突是難以避免的。這裡,我們來探討如何使用 GitLab 解決合併衝突,並瞭解如何同步本地與遠端的儲存函式庫。

使用 GitLab 解決合併衝突

假設你正在 new-login-message 分支上修改 login.py 檔案。在提交了一些更改並建立了合併請求後,你發現你的請求被合併衝突阻擋了。這是因為另一位開發者已經對同一行進行了修改,並將其合併到主分支中。

在這種情況下,GitLab 提供了兩種選擇:使用內建的 GUI 工具解決衝突,或在本地手動解決衝突。這裡我們將重點介紹如何使用 GitLab 的內建工具來解決合併衝突。

使用 GitLab 內建工具解決衝突

  1. 點選「Resolve conflicts」:這會帶你進入一個頁面,顯示哪些行存在衝突。
  2. 選擇保留的修改:假設你修改了一行文字「We’re glad you’re here」成為「We’re really glad you’re here」,而另一位開發者修改為「We’re super glad you’re here」。你決定保留自己的修改。
  3. 點選「Use ours」:這告訴 GitLab 保留你的修改並丟棄其他人的修改。
  4. 提交更改:輸入提交訊息並點選「Commit to source branch」,GitLab 會在你的分支上建立一個新的提交來解決衝突。

同步本地與遠端儲存函式庫

Git 的分散式架構意味著每個開發者都擁有一份完整的專案儲存函式庫副本。保持這些儲存函式庫同步是至關重要的,因為如果各自的儲存函式庫內容不同,團隊成員之間就無法看到彼此的工作。

  1. 設計金標儲存函式庫:團隊需要指定一個儲存函式庫作為「金標儲存函式庫」,這個儲存函式庫包含最新穩定版本的程式碼。只有將更改提交到這個儲存函式庫,它們才被視為專案的一部分。
  2. 同步本地與遠端:使用 Git 命令來同步本地和遠端儲存函式庫,確保所有成員都有最新的程式碼。

具體實作範例

假設我們有一個簡單的 login.py 檔案,其中包含以下內容:

print("We're glad you're here")

假設你在 new-login-message 分支上將其修改為:

print("We're really glad you're here")

同時,另一位開發者在主分支上將其修改為:

print("We're super glad you're here")

這時候,當你嘗試合併 new-login-message 分支到主分支時,會發生合併衝突。以下是使用 GitLab 解決衝突的具體步驟:

# 在 GitLab 上點選 "Resolve conflicts"
# 在衝突頁面中選擇 "Use ours" 按鈕
# 提交更改並完成合併請求

內容解密:

  • 程式碼邏輯:在這個範例中,我們展示瞭如何處理簡單的文字行衝突。當多個開發者對同一行文字進行修改時,Git 會標記出衝突。
  • 設計考量:GitLab 提供了內建的 GUI 工具來幫助開發者快速解決簡單的合併衝突。這對於需要快速解決問題並繼續工作的開發者來說非常方便。
  • 技術原理:Git 的合併機制會檢查每一行是否有多個版本的更改。當檢測到衝突時,Git 會標記出問題並等待開發者手動解決。
  • 潛在改進點:對於更複雜的合併情況,可能需要使用更強大的第三方工具來幫助解決衝突。此外,定期進行程式碼審查和協作可以減少合併衝突的發生。

檢檢視示

此圖示展示瞭如何使用 GitLab 解決合併衝突:

@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

內容解密:

  • 圖示邏輯:圖示展示了從檢視合併請求開始,到判斷是否有衝突、點選「Resolve conflicts」、選擇「Use ours」以及提交更改的一系列步驟。
  • 邏輯關係:圖示中的每一步都是依據前一步的結果來進行判斷和操作。
  • 詳細說明:透過圖示可以清晰地瞭解如何在 GitLab 上解決簡單的合併衝突。每一步都有明確的操作指引,幫助開發者快速解決問題。