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 Repositories (右側)「New」按鈕 Repository name: blog,勾選 Private (私密) 選項 Create repository

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

∗ 建立本機端儲存庫

▸ 在 Eclipse 中設定 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 檔案, 將不需版本控制的資料寫入,在上推或下拉時就會忽略這些檔案或目錄:

blog/
   blog/
   .gitignore
   .project
   .pydevproject
   manage.py
內容如下:
*~
__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

版本控制工具紐

▸ 可在 Eclipse 工具列加上版本控制按鈕,方便操作:Window Perspective Customize Perspective... (上方頁籤) Action Set Availability 勾選 Git Apply and Close

▸ 工具紐:

commint:commit ( Commit and Push)
commint:pull

(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 "base"]
    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)

▸ 練習