什麼是 Git?為什麼軟體工程師一定要會?

如果你想當軟體工程師,或是你身邊有朋友是軟體工程師,那麼你一定聽過 Git!說不定你也有聽過 GitHub,但你可能不知道兩者之間的關係是什麼,或是根本不知道要怎麼用他。

沒關係!這篇我們就要來介紹到底什麼是 Git,為什麼在軟體工程的世界裡他這麼重要,也會帶大家一步一步來安裝並且試跑幾個指令!

什麼是 Git

根據維基百科 和 Git 的官方網站,我們知道 Git 是一個「分散式的版本控制系統」,它可以讓開發者追蹤程式碼、整合新的更動、或是恢復成舊有的版本。它也可以讓你在程式碼所做的更動去和遠端的私服器相互同步。

這幾年來,更因為 Git 的可擴展性和廣大的受眾,讓 Git 在軟體產業變得不可或缺,甚至變成一個產業標準。幾乎所有的作業系統、開發環境、或是命令行工具都支援 Git。

但是我相信講了以上這些你還是會問所以 Git 到底是什麼。簡單來說,它就是一個幫助紀錄你打程式碼的歷程的一個工具。並且透過這個工具,開發者之間也可以非常輕易地互相合作。

什麼是 GitHub

GitHub 是一個用於軟體開發的雲端網頁平台。它提供一個合作環境,來自世界各地的開發人員可以在上面管理程式碼,或是和其他人共同開發一套專案。

GitHub 提供了很多軟體開發所需要的功能,包括前面提到的 Git 版本控制、或是問題跟蹤和 Pull Request 等等。讓團隊更容易一起工作、追蹤不同人進行的更改,甚至是進行程式碼的審查。

它被廣泛應用在開源項目和私人團隊合作,以分散和高效的方式管理和參與軟體開發專案。近年來,也越來越多軟體產業公司引進 GitHub 作為他們的程式碼管理平台。

所以現在 Git 和 GitHub 的關係應該就很清楚啦!本質上,Git 是一個版本控制工具,而 GitHub 則是一個基於 Git 的軟體服務和合作平台。

為什麼要用 Git

重要的問題又來了!那所以我們為什麼需要用 Git 呢?

我們來試想一個情景,今天你正在製作一個網站,這個網站的資料以及程式碼你都放在叫做 /website 的資料夾中。有一天你在網站上做了一個大的改動,但是在發布之後,你發現這個大改動會導致你的網站掛掉。為了恢復網站運行,你需要將所有的程式碼以及資料一個一個復原,但是更動實在太大了導致你沒辦法記得你到底哪些檔案有動過哪些檔案沒動過。這樣要怎麼辦呢?

有一個解決辦法,也可能是在學 Git 之前我們大多數人會做的事,那就是先將原本的 /website 資料夾整個複製一個,叫做 /website_2,並在 /website_2 裡進行更動,確定 /website_2 可行後,我們再用他來取代原本的 /website 資料夾。

但有沒有可能我們又同時想在原本的網站上測試另一個功能呢?這樣我們可能就會建立好多個資料夾,而這每個不同的資料夾之間的關係、差異等等,過不了幾天我們一定就會搞不清楚了。更慘的是,如果有其他人和你一起開發這個網站,那如果他哪天建立了新的資料夾,或是不小心取代了原本的資料夾,你就會完全不知道在幹嘛了。

上述的這些問題,Git 都可以幫你解決!前面講到 Git 是一個版本控制系統,它會幫我們保留所有的歷史紀錄,以及誰做了什麼改動,或是兩個版本之間的差異等等。這些資訊都可以非常輕易的取得!

接下來我們就來看看 Git 到底是如何做到的吧!

運作原理

簡單來說,Git 會將我們的文件還有開發的歷程儲存在本地端中。每當我們保存所做的更改時,Git 就會創建一個 commit。commit 是目前文件的一個快照,這些 commit 彼此互相連接,形成一個開發歷史圖,如下圖。

這個功能讓我們可以回到之前的 commit,比較各個 commit 之間的差異,或是查看專案的進展。commit 是由一個且唯一的一個哈希值來代表。

接下來讓我們來深入講一下幾個觀念,包括 commit 和 branch。

commit

在 Git 的世界裡,每個檔案都有三種狀態:已提交 committed已修改 modified已暂存 staged

  • 已提交 committed:代表此檔案已經安全的被儲存到 Git 數據庫中。
  • 已修改 modified:代表此檔案被修改了,但還沒被儲存到 Git 數據庫中。
  • 已暫存 staged:代表一個已被修改的文件被做上了標記,這讓這個檔案可以被包含在下次的提交中。

因此 Git 的基本流程是這樣的:

  1. 在本地端修改了文件,此時進行的修改還沒有進到 Git 資料庫中。
  2. 將修改加到暫存區 staged area。
  3. 將暫存區裡的所有修改提交到 Git 資料庫中。

值得注意的是,我們可以「選擇性」的將修改加到暫存區。什麼意思呢?就是我們不一定要將所有做的修改都加入這次的暫存區,我們可以選擇只將部份的修改加入。

比如說當我同時修改了兩個文件 ab,我可以先將對 a 的修改加入暫存區並提交。之後再將對 b 的修改加入暫存區並提交。這讓我們每次的提交都不會有太大的更動。

這有什麼好處呢?好處是我們可以很清處的知道每次提交的差異是什麼,以及如果我們想要捨棄掉某次的更動時也會相對容易一些。

我知道光看這些敘述可能還是沒有太懂。沒關係,我們要先了解這些名詞以及運作模式,之後我們會實做一些例子讓大家更加了解!

branch

接下來讓我們來說說另一個 Git 中的重要觀念:分支 branch。

在 Git 中,branch 就像是開發的不同路線,允許我們在不影響主要程式碼的情況下處理項目的不同方面。就好像前面的 /website 例子,當我們另外創建一個資料夾 /website_2 時,就好比在 Git 中創建了另一個分支。

我們來想像一下,假如我們正在寫一個故事,決定探索一個不同的結局。與其直接對原始故事進行修改,不如創建一個副本(分支)來測試一下新的結局。這樣一來,我們的主要故事保持不變,同時我們也可以自由嘗試和發展替代版本(分支)。一旦我們對新的結局感到滿意,就可以將這個分支合併回主故事中。

在 Git 中,分支提供了一種靈活而且安全的方式,可以在不干擾項目整體進度的情況下進行不同功能或修復的工作。這在多人合作的大型專案中尤其有用!

實際應用

講了這麼多,終於我們可以來看到底要怎麼用 Git 了!

我們會利用 Git 創建一個測試專案,利用 GitHub 當作我們的遠端私服器,並運行一些基本但重要的指令來看看我們該如何使用 Git,以及 Git 和 GitHub 之間的關係。

下載 Git

第一步當然啦就是從下載 Git 開始!Git 可以支援多種作業系統,包括 macOS、Linux、和 Windows。在這邊我們用 macOS 的方式來下載,其他的下載方式可以在官網的下載區中找到!

在 mac 中下載 Git 非常簡單,只需要跑以下指令就可以啦

$ brew install git

在下載完成後,我們必須要設定 Git 的使用者以及 email,這個資訊會在之後提交時被取用

$ git config --global "user.name"
$ git config --global user.email "[email protected]"

我們可以利用下面的指令來確認設定成功

$ git config --get user.name
$ git config --get user.email

建立專案

接著我們到 GitHub 創建我們的帳號,創建帳號的步驟在這裡我就不講啦,這應該不用教學了。

創建好帳號後,我們就可以在 GitHub 創建專案啦!我們到「Repositories」並點擊「New」來新增專案

在上面的圖片中我們看到幾個被紅色框框。第一個是標題,命名我們的專案名稱。第二個是描述,雖然不是必要的,但通常我都會加,這會讓其他人馬上就能知道你這個專案在做什麼事。第三個是設定為是否公開,因為這是測試專案,我不想讓其他人看到,所以我設為私人專案。最後我則會增加 README 檔案,這是一個利用 markdown 寫出來的檔案,主要是用來更詳細的介紹專案的目標、如何執行專案等等。

設定完這些之後我們就可以按下建立按鈕啦。建立完成後,我們就會在 GitHub 上看到專案啦!

接下來我們點開綠色的「Code」,並點選「SSH」會看到一個連結,請複製那個連結,打開電腦上的終端機,並執行這一行指令

$ git clone [email protected]:yahsiuhsieh/git-project.git

這一步驟是將在 GitHub 上創建的專案複製到本地端,並建立連結。

如果你遇到類似 Public Key Permission Denied 的錯誤訊息的話,請你先依照新的 SSH 密鑰並将其添加到 ssh-agent 以及新增 SSH 密鑰到 GitHub 帳戶來建立密鑰。

若是成功複製,我們會看到類似這樣的結果,並看到一個有同樣名稱的資料夾被建立了出來。

Cloning into 'git-project'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.

提交 commit

接下來,讓我們提交一次 commit 吧!

我們先在 README.md 裡面新增一個小標題,這會讓 README.md 這個檔案變成「已修改 Modified」的狀態

$ echo "## Step one" >> README.md

我們可以利用 git status 這個指令查看當前的狀況,我們可以發現,README.md 確實是「已修改 Modified」

接著,我們要將這個修改的檔案放到「暫存區 Staged」

$ git add README.md

一樣我們利用 git status 來查看檔案狀態,我們可以看到狀態從紅色變為綠色,代表檔案已被放入暫存區。

最後我們就可以來提交 commit 啦!我們利用以下的指令提交,-m 後面接著是你想註記的訊息。

$ git commit -m "this is my first commit"

這樣就提交完成啦!是不是很容易呢!

但到目前為止,我們都只是在本地端執行,想要讓這個提交上傳到遠端私服器,也就是 GitHub,我們要執行 git push 的指令

$ git push

Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 303 bytes | 303.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:yahsiuhsieh/git-project.git
   64f7b4e..f4c3872  main -> main

接著我們到剛剛建立的 GitHub 專案頁面查看 commits 歷史資訊,我們就可以看到我們提交的 commit 啦!並且剛剛對 README.md 的修改也會顯示在 GitHub 中。

建立 branch

接著我們來講講該如何建立以及運用分支。

前面我們說到,當我們想要開發另外一個路線,但同時不想影響到主要程式碼的時候,我們就可以利用分支。這邊讓我們來建立一個分支,並在分支上創立一個新的檔案 test.txt,完成之後再合併進主要程式碼。

首先,我們要先利用以下指令建立分支

$ git checkout -b feature/test

這個指令會建立一個叫做 feature/test 的分支。我們接著可以利用 git branch 的指令列出所有分支,以及查看我們當前所在的分支上。

現在,我們已經在一個分支上了。我們來新增一個 test.txt 的檔案,並利用前面講的,修改檔案,提交 commit,然後 git push 到 GitHub 上。

$ echo "this is a test file" >> test.txt
$ git add test.txt 
$ git commit -m "commit in another branch"
$ git push -u origin feature/test

值得注意的是,git push 和前面有點不太一樣,這是在告訴 Git 我們是要將本地端新增的 branch 上傳到 GitHub,而不是普通的 commit。

做完這些後,我們就再次移動到我們的 GitHub 專案頁上,我們可以看到現在有兩個分支了!你可以點點看並查看一下兩個分支的內容有什麼不一樣!

提交 pull request

讓我們先了解一下什麼是 pull request

其實觀念非常簡單,就是當有一個測試好的故事分支想要合併到主要劇情中,我們就要建立一個 pull request,通知程式碼的負責人(在這個例子就是我們自己),請他審核一下分支。如果審核通過,那麼就可以被合併到主要劇情中。

以下我們直接來示範如何建立一個 pull request

本地同步

最後一步就是要將 GitHub 的東西同步到本地端啦!在合併 pull request 後,GitHub 上的資料已經和本地端不同了,我們現在要做的是再一次將本地端的資料和 GitHub 上的長得一模一樣。

我們接著回到終端機執行這個指令

$ git pull

這個指令就是將 GitHub 上的資料給抓取下來,進行同步。

同步完成後,我們可以執行 git log 查看 commit 的資訊。我們再去和 GitHub 上的 commit 做比較,會發現提交的歷史紀錄都一樣!

結尾

到這邊我們就介紹完 Git 的基本架構啦!當然啦,Git 遠遠不止這些,還有很多進階觀念比如說 merge、conflict、rebase 等等,而這些觀念在軟體工程的領域中也是非常常見而且重要的。但這些觀念都建立於 commit 與 branch 上,我們必須先瞭解基本才能了解更多。

另外有一個我覺得很棒的 Git 練習網站:學習 Git 分支

透過自己打指令以及利用動畫顯示結果,我相信一定可以讓大家對於 Git 的分支了解更進一層樓。我自己就是透過這個網站練習的噢!

那我們這篇就講到這啦,有機會的話下一篇我們再來講講其他進階觀念與指令!