Django -- 從平凡到超凡

第 4 章    版本控制

(1) 版本控制

∗ 版本控制 (Version control) 功能

▸ 有系統地記錄資料異動的內容、時間、異動者等,讓系統開發歷程有完整的記錄

▸ 提供比對功能,以了解資料異動前後的差異及其理由

▸ 專案可以往前回復到某個時間點的版本 (因此專案絕不會被搞壞! ;-)

▸ 可以分叉 (Fork),從某個點延伸出另外一個專案分支 (Branch)

▸ 多人共同開發同一專案時,協調開發者之間的資料異動

註:本教材僅 應用 版本控制系統,版本控制的概念及理論則非探討的範疇

∗ 版本控制系統

版本控制系統 (Version control system, VCS) 主要分成兩類:

✶ 集中式,例如:Subversion (SVN)
✶ 分散式,例如:Git, Mercurial

Github:提供雲端 Git 版本控制服務 (目前約有 1,000 萬個專案)

EGit:在 Eclipse 的 Git 插件

版本控制的重要性

作者曾上過一門系統開發課程,課中講師提及:如果你所待的公司沒有使用版本控制,那就趕快離職! 如果不想離職,那就幫公司導入版本控制!

(2) 進入版本控制

∗ 建立 Github 雲端儲存庫 (Repository)

▸ 註冊:我們將利用 Github 所提供的分散式版本控制服務,首先至 Github 註冊帳號

▸ 建立儲存庫:點選 (右上角) 使用者頭像 --> Your profile --> Repositories 頁籤 --> 「New」按鈕 --> Repository name: blog (可選擇公開 Public 或私密 Private, 公開免費、私密需付費) --> Create repository

▸ 需要的話,可加入協同開發者:至 blog 專案頁面 --> (右上角) Settings 頁籤 --> (左方) Collaborators (可能需要再次輸入密碼) --> Search by username, full name or email address 欄位: 輸入協同開發者帳號 (Github會自動搜尋) --> Add collaborator

∗ 建立本機端儲存庫

▸ 在 Eclipse 中設定 Git 版本控制 (回顧第 2 章:設定 Git 版本控制)

✶ 預設 Git 目錄:Window --> Preferences --> Team --> Git --> (右欄) Default repository folder: /home/<username>/webapps/git --> Apply and Close
✶ 選擇 Commit 對話框的模式:Window --> Preferences --> Team --> Git --> Committing --> (右欄) 取消勾選 Use Staging View to commit instead of Commit Dialog --> Apply and Close

▸ 建立儲存庫:Right click project --> Team --> Share Project --> 選 Git --> Next --> Repository: Create --> Repository directory: /home/<username>/webapps/git/blog --> Finish --> Finish

▸ 儲存庫建立之後,blog 專案即進入版本控制,而且 Eclipse 將專案移至 /home/<username>/webapps/git/blog 下 (多一層 blog 目錄),目錄結構如下:

webapps/
   git/
      blog/
         .git/
         blog/
            blog/
            manage.py
            ...
.git/ 是版本控制目錄, 裡面記錄專案的所有資料以及每次資料異動的記錄, 如前所述,Eclipse 將此目錄與專案目錄並列 (亦即「隔開」)

∗ 修改 config 設定檔以設定遠端 Git repository 資料

/home/<username>/webapps/git/blog/.git/config

[core]
    repositoryformatversion = 0
    filemode = true
    logallrefupdates = true
[remote "origin"]
    url = https://github.com/<gitUsername>/blog
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master

remote "origin":遠端 (Remote) 的分支稱為 origin

branch "master":本機端 (分支,Branch) 的分支稱為 master

<gitUsername>:您在 github 所註冊的帳號

隱藏檔案

∗ 上推 (Push) 至 Github

▸ 某些檔案或目錄不需要版本控制,可以在專案目錄下建立 .gitignore 檔案, 將不需版本控制的資料寫入,在上推或下拉時就會忽略這些檔案或目錄

<project>/.gitignore:
*~
__pycache__
*.pyc
✶ 設定忽略的項目:
# 檔名以波浪符 (~) 結尾:備份檔案
# __pycache__ 目錄:Python 的二元執行檔目錄
# 檔名以 .pyc 結尾:Python 的二元執行檔

▸ 執行 Push to Github:Right click project --> Team --> Commit --> (Eclipse 可能詢問 Username 與Email: Name: xxx, Email: xxxx@xxx.xxx (勾選 Don't show this dialog again) --> OK --> Commit message: First push --> 勾選所有檔案 --> Commit and Push --> 輸入 User 與 Password --> OK --> OK

▸ 可以至 Github 網站檢視 Push 的結果

∗ 協同開發者將 Github 上的專案匯入 Eclipse

▸ File --> Import --> Git --> Projects from Git --> Next --> Clone URI --> Next --> URI: https://github.com/<gitUsername>/blog --> Next --> 勾 master --> Next --> 目錄:/home/<username>/webapps/git/blog --> Next --> 勾 Import existing Eclipse projects --> Next --> 勾 blog --> Finish

∗ 後續 Push 與 Pull

▸ Push:本機端的新資料更新到雲端

Right click project --> Team --> Commit --> Commit message: xxxxxxxx --> Commit and Push --> 輸入 User 與 Password --> Next --> OK

▸ Pull:雲端的資料更新到本機端

Right click project --> Team --> Pull --> OK

∗ 在 Github 比較檔案前後版本內容差異

▸ 進入專案根目錄 (記得有兩層:blog/blog) --> (右上方) History --> 點所需要的 Commit 版本

∗ 在 Eclipse 中比較檔案前後版本內容差異

▸ 右鍵點檔案 --> Compare With --> Previous Revision

(3) 版本控制流程範例

∗ 範例 1:開發者 A 與 B 協同開發同一專案,自由上推或下拉

▸ 流程圖:

gitPullPush
  1. A 在 Workspace 建立 Project (版本 0)
  2. A 的 Project 進入版本控制 (版本 0):在本機端的儲存庫 (Local repository, Repo A)
  3. A 上推至 Github (版本 0)
  4. B 下拉 (版本 0)
  5. A 修改 (版本 1)
  6. A 上推 (版本 1)
  7. B 修改 (版本 2)
  8. B 下拉 (版本 3:合併版本 1 與 2)
  9. B 上推 (版本 3)
  10. A 下拉 (版本 3)

∗ 範例 2:開發者 A、B、與 C 協同開發同一專案,程式需經過對方檢視並同意後才合併

▸ 範例 1 中,開發者可自由上推下拉資料,但結果可能是一堆人上推下拉了一堆垃圾,較為嚴謹的作法應該要導入「程式檢視」 (Code review) 程序:

✶ 程式修改後,開發者發出下拉請求 (Pull Request, PR) 訊息給程式檢視員
✶ 程式檢視員檢視程式,如果有問題,通知開發者修正,修正完後開發者再次發出下拉請求,此程序可能重複多次
✶ 程式檢視通過後,程式檢視員 (或專門負責者) 將修正後的程式合併 (Merge) 到主分支

▸ 開發者 A 與 B 均修改其 config 設定檔:加入主分支

/home/<username>/webapps/git/blog/.git/config
[core]
    repositoryformatversion = 0
    filemode = true
    logallrefupdates = true
[remote "origin"]
    url = https://github.com/<gitUsername>/blog
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[remote "main"]
    url = https://github.com/<gitUsernameC>/blog
    fetch = +refs/heads/*:refs/remotes/origin/*
remote "main":遠端增加另一分支 main
<gitUsername>:開發者 A 或 B 在 github 所註冊的帳號
<gitUsernameC>:開發者 C 在 github 所註冊的帳號,亦即主分支的擁有者帳號

▸ 流程圖:

gitPRMerge
  1. C 在 Workspace 建立 Project (版本 0)
  2. C 的 Project 進入版本控制 (版本 0)
  3. C 上推至 Github (版本 0,主分支)
  4. A 建立分支 (版本 0,A 分支):在 Github 主分支儲存庫右上方按下 Fork 按鈕
  5. A 下拉 (版本 0)
  6. B 建立分支 (版本 0,B 分支)
  7. B 下拉 (版本 0)
  8. A 修改 (版本 1)
  9. A 上推 (版本 1)
  10. A 發出下拉請求 (Pull Request, PR)
  11. B 檢視程式無誤後,將 A 分支合併到主分支 (版本 1):在 Github Pull Request 頁面按下 Merge 按鈕
  12. B 修改 (版本 2)
  13. B 上推 (版本 2)
  14. B 下拉主分支 (併入版本 1,產生版本 3):Right click project --> Team --> Pull ... --> Remote: main: https://github.com/<gitUsernameC>/blog --> Finish
  15. B 上推 (版本 3)
  16. B 發出下拉請求
  17. B 發出下拉請求,A 檢視程式無誤後將 B 分支合併到主分支 (版本 3)
  18. A 下拉主分支 (併入版本 2,產生版本 3)
  19. A 上推 (版本 3)

上一章       下一章