2019-05-29

git 與 GitHub 基本概念與操作

版本控制對程式設計人員是極重要,不可或缺的功能。而 git 是眾多版本控制系統中的佼佼者,也是目前最主流的選擇,甚至可以說『沒有之一』。它的功能強大,因此難懂難精。好在上手不難,只要了解幾個基本指令就能發揮功能,提供很大的助益。本篇介紹最基本的 git 概念和指令,讓您可以快速上手並開始使用…


學習目標
  • 了解 git 和版本控制基本概念
  • 了解 git 和 GitHub 的差異
  • 建立本地 git repository 檔案庫及基本操作
  • 建立 GitHub 遠端檔案庫、上傳檔案庫、建立協同合作專案
  • 常見的衝突問題和解決

為什麼需要版本控制系統
git 官方文件 (git Documentation - Pro Git book) 在《About Version Control》章節將為什麼需要版本控制,以及版本控制系統 Version Control System (VCS) 應有的功能與各類型差異作了詳細的說明:"What is “version control”, and why should you care? Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later."
簡單地說,程式和系統的開發包含非常多且複雜的程式碼、相關資源以及人員,而且過程會不斷重覆設計和修改,因此需要版本控制系統記錄和控管開發過程每個階段的版本。

什麼是 git
git 是一套免費且開源 (open source) 的分散式版本控制系統,它可以快速又有效率的管理個人小型專案到多人超大型專案,是目前最主流的版本控制系統。最初由林納斯·托瓦茲 (Linus Torvalds) 創作,於2005年以 GPL (GNU通用公共授權條款) 釋出。
git 提供 Mac OS X、Windows、Linux/Unix 各種作業平台版本,任何人、任何公司都可以免費自由下載使用,建立個人或團隊的分散式版本控制系統。

git 和 GitHub 的差異
git 是一套軟體系統,而 GitHub 則是運用 git 提供程式原始碼版本控制與代管服務的服務平台,由 GitHub 公司營運,該公司於2018年6月被 Microsoft 收購。GitHub 同時提供付費帳戶和免費帳戶,目前是世界最大的程式碼存放網站和開源社群。

git 基本概念
本篇以快速上手開始使用為目標,因此只說明基本運用需要了解的概念。以下這張圖大概是使用 git 非懂不可的最最基本概念了:
Source: git Documentation - Pro Git book

git 控管下的檔案有三個主要狀態,對應到圖中的三個區塊:
  • Modified (修改):正在處理、工作中的程式檔,對應到上圖的 Working Directory (工作目錄)。剛開始寫或原已寫好但又被修改了的程式檔都在這個區塊。
  • Staged (暫存/過渡):已經寫好或修改好了,也已確定沒有問題,準備送出到檔案庫中,對應到 Staging Area (暫存區/過渡區),也被稱為索引 (Index)。將已處理好的程式檔送到此區,提示自己這些是已完成的程式檔案。
  • Committed (提交):已確定完成並送入檔案庫的狀態,對應到 git directory (也稱為 git repository,檔案庫/儲存庫,後文將統一使用 repository,檔案庫)。已完成的程式檔,送進檔案庫保存。

為何要分成這三個狀態和區塊呢?
您可以想像您正在將很多要寄出的物品打包。Working Directory (工作目錄) 就是您手上正在整理中的物品,這裡是您的工作區。已經整理好的物品,您就會先放進箱子 (Staging Area,暫存區/過渡區) 裡,可能因為您想將寄給同一個收件人的東西都放進一個箱子裡,或想把同類型的東西都放一起,或是箱子還挺大的,想儘量放滿一點再寄出。所以都先暫放在箱子中,免得一不小心碰到又亂了。如果中途發現有東西放錯箱子,您就會把東西拿出來到工作區,再整理到對的箱子。該放的東西都放好了,或箱子都放滿了而且檢查無誤,您才會封箱寄出 (送進 repository, 檔案庫保存)。
這樣做的好處是,每個程式檔案的狀態會很清楚,任何有更動的檔案就會回到工作目錄,不會忘記那個檔案有更動。作好了覺得沒有問題,先移到暫存區中,提示自己這些是已經完成的。可能等到同一個功能項下的所有程式檔都處理好,都測試沒有問題了,再一起 Commit (提交) 到 repository (檔案庫)。

以下這張圖進一步延伸到遠端的檔案庫 (remote repository)。
Source: TechBridge 技術共筆部落格 - Git 與 Github 版本控制基本指令與操作入門教學

git 是分散式版本控制系統,而前述三個主要狀態和三個區塊都在您的電腦上 (git Documentation: "Nearly Every Operation Is Local")。如果您的專案是多人合作,那就需要進一步把電腦上的 local repository (本地檔案庫) 同步到網路上的遠端檔案庫 (remote repository),這樣團隊成員都能取用您完成的程式檔。
若是個人的專案,您可以只存到自己電腦的 local repository (本地檔案庫) 就好,但也可以把遠端檔案庫 (remote repository) 當作是程式原始碼代管存放空間,或跟眾人分享、協同合作,這就是 GitHub 的服務目的。
這張圖同時呈現了每個動作對應的指令:
  • 送入暫存 Staged:git add
  • 提交 Committed:git commit
  • 將本地檔案庫同步至遠端檔案庫:git push
  • 將遠端檔案庫合併至本地檔案庫:git pull

使用 git 建立 repository
對 git 有基本的了解,接下來就開始使用 git 看看吧!
安裝 git
若您是使用 Ubuntu 環境,通常 git 已安裝好。不然,您可以用這個指令安裝:
sudo apt install git
用此指令查看 git 的版本同時判斷是否安裝好了:
git --version
Windows 及 macOS 系統的安裝可到 Git Downloads 下載安裝檔,執行並以「下一步」完成安裝,詳情請參考《Pro Git book: 1.5 Getting Started - Installing Git》。

本篇教學將以 Ubuntu 環境為主,Ubuntu 使用者請以 Ctrl + Alt + T 開啟終端機 (命令視窗),Windows 使用者則可在安裝好的 Git 中找到 Git Bash 執行,建立一個專門放置要用 Git 控管的資料夾後,進到該資料夾下開始以下的操作。

設定使用者
開始使用 git 前要先設定使用者名稱和 Email 信箱,只需設定一次。若已有 GitHub 帳號,建議和 GitHub 使用相同的名稱和 Email;若還沒有就用自己常用的。
git config --global user.name "<Your Name>"
git config --global user.email "<your@gmail.com>"
設定好了以後,再用這個指令檢視設定結果:
git config --list   # 檢視 git 設定

新增 repository
將介紹 2 種新增 repository 的方式,第一個是在自己的電腦 (本地 local) 從無到有建立一個全新的 repository。
可以把 repository 檔案庫想像成就是一個專案 project,在 git 裡是以目錄 / 資料夾呈現。所以新增 repository 的第一步就是先新增一個資料夾。
mkdir my_git  # 建立一個名為 my_git 的資料夾,注意:git 預設為區分大小寫,Ubuntu 也是
cd my_git     # 切換至 my_git 資料夾
git init      # 初始化這個目錄,讓 git 對這個資料夾進行版本控制,建立 git repository 檔案庫
ll            # 看一下資料夾內有什麼
執行 git init 後會發現資料夾內多出了 .git 這個隱藏資料夾,裡面存放 git 對這個 repository 的控制資料。這時候一個名為 my_git 的檔案庫就建立好囉。

增加檔案
接下來用 vi 編輯器 (Windows 使用者可用 Notepad++ 等文字編輯器) 在 my_git 資料夾內新增一個 hello.py 的 Python 程式檔:
vi hello.py
檔案內加入一個輸出的函式:
print("Hello git!")    # Python輸出函式
將 hello.py 存檔離開後,執行 git status 顯示目前工作目錄的檔案狀態:
git status   # 顯示目前工作目錄的檔案狀態
執行後會看到 git 回覆 my_git 專案的狀態,有一個新增的工作中 (Modified) 檔案 hello.py,還在工作目錄中,沒加到 Staging Area (暫存區/過渡區)。git 還會提醒以 git add <file> 指令把檔案加入暫存區。

加入暫存區
如果這個程式檔完成了,就可以使用 git add <file> 加入暫存區。如果想將工作目錄內的所有檔案都加入暫存區則可用 git add . (dot, git 2.x 之後等同於 git add --all)。執行下列指令:
git add hello.py   # 把 hello.py 加入暫存區
git status
會看到 new file: hello.py,表示 hello.py 被加入暫存區了。

提交至 repository
hello.py 沒問題了,接下來可以用 git commit -m <message>,將 hello.py 提交至 repository。-m 這個參數表示加上一段訊息說明這次的 commit,讓以後的自己或其他人知道這次 commit 作了什麼事。commit 訊息對日後追蹤程式非常重要。
git commit -m "Init hello.py"   # 留下 commit 訊息:新增了 hello.py 這個程式檔
git status
git 回覆所有的檔案都提交,工作目錄內沒有檔案了。

查看提交歷史記錄
git log 指令可以查看提交 commit 的歷史記錄,誰 (commit 的人) 在什麼時間作了提交,以及該次提交的說明 (commit 訊息)。
您可以繼續對 hello.py 檔案進行修改,用 git status 指令了解狀態的改變,以及多加幾個程式檔後,再加入暫存區及提交,並用 git log 指令查看記錄。

從 GitHub 下載一個專案
另一個建立專案的方式是從 GitHub 下載一個專案,然後把它變成自己的。我們以作者 Louie Lu (mlouielu/twstock) 在 GitHub 上的《台灣股市股票價格擷取 (含即時股票資訊) - Taiwan Stock Opendata with realtime》為例,先點這個連結到 GitHub: mlouielu/twstock,按下圖(1)位置的『Clone or download』按鈕,再按(2)『複製』,會將這個 GitHub 上的專案位置 URL 複製到剪貼簿中。
Source: Louie Lu (mlouielu/twstock)

回到終端機,先進到您想放這個專案的目錄中,然後輸入 git clone 貼上剛剛複製的 URL 將遠端的檔案庫複製過來。執行下列指令:
git clone https://github.com/mlouielu/twstock.git
查看一下目錄會發現多了一個 twstock 的資料夾,表示已將 mlouielu/twstock 的檔案庫複製過來了。
接下來進到 twstock 目錄中,因為這是一個從遠端複製過來的 repository 檔案庫,我們當然可以用 git status 查看一下 twstock 檔案庫目前的狀況,以及 git log 查看 commit 的歷史記錄:
cd twstock   # 一定要進到 twstock 目錄,git 命令才是針對該檔案庫
git status   # 查看 twstock 檔案庫的狀況
git log      # 查看提交歷史記錄
可以看到作者 Louie Lu 對這個專案很完整的提交記錄。
那要怎麼讓這個專案變成自己的呢?還記得前面新增 repository 時執行 git init 指令初始化目錄後,資料夾中會多出一個 .git 隱藏資料夾嗎?關鍵就是它了。只要刪除 .git 資料夾再重新初始一次,這個檔案庫就變成一個全新的專案,而且所有的程式檔都處於工作目錄中 modified 狀態。
rm -rf .git   # 強制刪除 twstock/.git 目錄下所有內容
git init      # 初始化 twstock 目錄
git status    # 再檢視一下目錄狀況
至此介紹了 2 種新增專案或說 git repository 的方式。接下來介紹怎麼把自己電腦裡的檔案庫 local repository 同步到遠端檔案庫,也可以說是「上傳至 GitHub」。

使用 GitHub 遠端檔案庫
第一步當然是要先:
註冊 GitHub 帳號
若您依本篇介紹學習 git,且還沒有註冊過 GitHub。那先執行以下指令,查看您設定的 git 使用者名稱與 Email,註冊 GitHub 時可以使用相同的名稱和 Email。
git config --list   # 查看設定的 git 使用者
github.com 首頁,到右邊的 Sign up 註冊,填上您的 Username & Email。只要綠色勾勾出現就表示您的名稱和 Email 可以使用。按下 Sign up for GitHub,跟著註冊步驟,選擇 Free 方案 (使用 Free 方案您上傳的所有專案都是公開的,任何人都可以查看內容和下載,若要建立私人的專案就必須付費!可以隨時升級 Upgrade 成付費方案。)
Source: github.com

如果原本設定的名稱已有人使用,改用其他名稱註冊,和電腦上的 git 不同怎麼辦?沒關係,在您的電腦上用下列指令改變使用者名稱就可以了:
git config --global user.name "<您的 github 使用者名稱>"   # 修改 git 使用者名稱
接著開啟您註冊時填寫的 Email 信箱,找到 GitHub 寄發的驗證 Email 完成驗證,就可以開始使用了。

新增 GitHub 檔案庫
在本篇介紹中,您會發現 git directory,repository,檔案庫/儲存庫以及專案 (project),這幾個名詞應該是同義的。的確如此,但為什麼登入 GitHub 後的首頁,以及右上角「+ 新增」選單中會有「Start a project」、「New repository」、「New project」不同的功能選項?
Source: github.com

repository 和 project 這兩個字在 GitHub 中仍然是相同的,都代表檔案庫 (repository)。「New repository」和「Start a project」功能都是新增一個檔案庫。而「New project」則是 GitHub 提供了名為「project boards (專案儀表板)」的功能,讓使用者方便管理檔案庫 (repository),尤其是協同合作的 repository。不用擔心,就用右上角「+ 新增」選單中的「New repository」新增一個檔案庫吧!接著會看到這個畫面。

前面的介紹中,已建立一個名為 my_git 的檔案庫,我們試著把這個在本地 (local) 建立的檔案庫上傳到 GitHub:
  • Repository name (必要) 就輸入 my_git 和本地的檔案庫名稱一致。
  • Description (非必要) 對檔案庫的說明描述,輸不輸入都可以。
  • Public / Private 如果註冊時選擇免費方案,所有的專案預設都是公開的。
下方 3 個選項都不用改變。因為我們要將電腦上已建立好的檔案庫新增上傳到 GitHub,若選擇了下列項目,GitHub 上的 my_git 檔案庫裡就會有本地 my_git 沒有的檔案,造成等一下上傳發生問題,需要額外的處理。簡單說明:
  • Initialize this repository with a README:為這個檔案庫自動建立 README 說明檔,以 markdown 語法加入了 Repository name 和 Description (記得不要勾,之後可以自己建立)。
  • Add .gitignore:要忽略的檔案清單,用來告訴 git 在版本控制記錄的時候忽略這些檔案,通常是程式中用到和資料庫帳號密碼有關的檔案 (保持 none,之後可以自己建立)。
  • Add a license:這個專案使用的授權方式 (也保持 none)。
按下 create repository 按鈕,就新增完成 GitHub repository 遠端檔案庫了。
接著會看到這個引導畫面,GitHub 提示我們接下來可以怎麼建立檔案庫的內容。先點選 HTTPS,這是我們接下來要用的方式。
Source: github.com

連結本地和遠端檔案庫
這時候我們電腦上的 my_git 檔案庫和 GitHub 上的 my_git 檔案庫互不知道對方,所以要先連結起來。連結的方法就是 GitHub 引導畫面中「…or push an existing repository from the command line」這個部份介紹的指令,先複製 git remote add origin <您的 GitHub repository URL> 這行指令。回到終端機,請記得要先回到 my_git 目錄下,再貼上執行:
git remote add origin <您的 GitHub repository URL>   # 連結 GitHub 遠端檔案庫

將本地檔案庫上傳 GitHub
再執行下一行指令:
git push -u origin master   # git push 將本地檔案庫上傳
接著要輸入您在 GitHub 上建立的 Username,接下 Enter 後再輸入密碼,就會看到本地的 my_git 檔案庫在上傳 GitHub 了。

回到 GitHub 引導畫面重整一下 (按下 F5, Reload),就會看到 hello.py 檔案出現了。
Source: github.com

您可以在電腦上的 my_git 專案中繼續新增程式檔,然後依照和前述相同的順序:
  • git add 加入暫存區
  • git commit -m "commit訊息" 提交至本地檔案庫
  • git push -u origin master 將本地檔案庫上傳遠端檔案庫
  • 輸入帳號和密碼
因為剛剛已經以 git remote add origin <您的 GitHub repository URL> 指令將本地和遠端檔案庫連結起來了,git 會記住它,以後不用再連結,直接 git push 就可以上傳遠端檔案庫。可以執行:
git config --list   # 查看 git 設定
就會看到 remote.origin.url=<您的 GitHub repository URL> 被存在 git 設定中了。

建立合作專案 Collaborators
如果我們想把這個新建立的 GitHub repository (專案/檔案庫) 和團隊成員共用,變成一個合作專案,要怎麼做呢?
  • 先點上方 my_git 專案的 Settings 頁籤
  • 再點左邊 Options 的 Collaborators 選項
Source: github.com

  • 出現新增 Collaborators 頁面
  • 對話框中輸入您要新增成員的 GitHub 帳號或 Email 搜尋成員
  • 選擇搜尋到的成員按下 Add collaborator 進行邀請
  • 重覆搜尋並邀請成員
  • 等待被邀請成員回應邀請
Source: github.com

被邀請參與合作專案者
被邀請的成員,當然一定要有 GitHub 帳號,會收到一封邀請 Email,點 View invitation 檢視邀請後,會登入 GitHub 並看到這個畫面:
Source: github.com

按下 Accept invitation 接受邀請,被邀請的成員就會看到 my_git 這個專案的內容,出現在自己的 GitHub 帳號中,並可以看到有目前有 2 位 contributors 在此 repository (專案/檔案庫)。
Source: github.com

被邀請的人要怎麼建立與使用這個專案呢?步驟其實和之前相同:
◆ 先把專案 clone 到自己的電腦 (本地 local)
按下「Clone or download」複製 URL,執行:
git clone <貼上 URL>
◆ 在此專案目錄下工作處理
◆ 處理好的程式檔加入暫存區 git add
◆ Ok了,進行提交 git commit
◆ 要 push 到 GitHub 之前...
因為這裡是多人協同合作,在你處理的同時,可能也有其他協同者在處理此專案。其他協同者若 commit 處理並上傳 (push) 至 GitHub,就會造成目前在 GitHub (遠端檔案庫)上的版本比你電腦上的新 (因協同者是在你 clone 至自己的電腦後上傳的)。這時候會產生版本衝突,你的 push 會失敗並出現錯誤訊息 (常見的衝突問題將在下一節討論!)。
建議協同合作專案成員,在每次要開始工作前,和 push 你的處理到 GitHub 前,先把目前 GitHub 上最新的檔案庫更新 (拉取 pull) 到自己的本地檔案庫,讓你的本地檔案庫和 GitHub (遠端檔案庫)上的版本一致。執行:
git pull origin master   # pull 更新本地檔案庫
◆ 上傳 / 同步至 GitHub
git push origin master   # push 上傳檔案庫
你是否發現這次過程我們沒有執行 git remote add 來連結本地和遠端檔案庫。因為在 clone 下來時 .git 中已經包含了原本的遠端檔案庫 URL 了,可以執行這個指令檢視:
git remote -v   # 檢視遠端檔案庫
這樣就可以和多人協同合作專案了。

常見的衝突問題和解決
多人協同合作專案很容易發生版本衝突問題。


git 學習資源
git 還有很多重要的概念,如衝突處理、分支和合併。但若是個人使用的最小概念需求,以上就夠了。另外,視窗介面的 git 工具對使用 git 並不是絕對必要的,本篇不介紹視窗介面 git 工具的使用,完全在 Ubuntu 終端機下進行。若有興趣繼續深入了解 git,可以參考以下由網路上眾多高手撰寫,非常詳細且免費的 git 教學資源 (介紹順序無任何意義!):


參考資料 (References):
😺 git 官方文件:git Documentation - Pro Git book
😺 git 維基百科
😺 GitHub 維基百科