[week 1] 版本控制 - Git 進階指令 & GitHub
- 發佈時間
本篇為 [GIT101] Git 超新手入門 這門課程的學習筆記。
在上一節我們學到 Git 基本指令,接下來要學習什麼是 Branch(分支),以及如何送出的 Pull Request 進行共同開發,以及介紹提供視覺化介面操作 Git 的 GitHub。
已複製!學習目標: 知道怎麼使用 branch 並送出 Pull Request 熟悉 Git Workflow(也就是交作業的流程)
為什麼需要 Branch(分支)?#
簡言之,Branch 的作用就是讓開發過程各自獨立。
例如:今天公司產品在開發新功能,途中發現有個嚴重的 bug 必須修正#
若以一條線的開發模式(如同上一節學的 Git 基本指令):#
- 在同一個 commit 上進行修改,容易產生衝突
穩定版 + bug fix
還參雜未完成的新功能,也可能產生更多問題
若能分成「穩定版本」和「新功能開發」,兩條分支就不會互相干擾:#
穩定版 + 修好 bug
→ 得到新的穩定版- 待新功能開發完成,即可合併得到有新功能的版本,成為最新的穩定版
操作 branch 基本指令#
使用 Git 進行版本控制時,系統最初會自動建立第一個 branch ,也就是 master
。
git branch -v
:查看目前在哪個分支#
下列訊息分別表示:分支名稱、版本號、版本訊息。
git branch
:如果後面沒接任何參數,只會顯示目前有哪些分支。
git branch <branchName>
:新增分支#
提醒:開發新功能之前,養成開新分支的好習慣!
git branch -d <branchName>
:刪除分支#
git checkout <branchName>
:切換分支#
和上一節的切換版本指令原理相同,這裡是將 <版本號碼>
換成 <分支名稱>
git checkout <版本名稱>
:切換版本git checkout <branchName>
:切換分支git branch checkout -b <branchName>
:「新增」並「切換」到該分支
如何合併分支?#
git merge <branchName>
:把分支合併進來#
範例:把分支 new-feature
合併到 master
#
- 輸入
git checkout master
切換到master
這個分支 - 輸入
git merge new-feature
,完成基本的分支合併 用git log
查看版本紀錄,可知「合併」的過程會自動建立一個新版本
- 成功合併後,即可刪除分支
new-feature
那在合併時發生 conflict(衝突)怎麼辦?#
所謂的衝突,就是「同一份檔案的兩個版本,裡面有一個或多個不同的內容」。
但是 Git 無法幫你選擇哪一個當作最終版本,所以當發生衝突時,只能「自己手動調整」。
範例:在 master
和 new-feature
這兩條支線上,均改了同一個檔案 code.js
#
- 此時若把分支
new-feature
合併到master
上 - 顯示發生衝突,輸入
git status
可見提示說明:該檔案的兩個版本均有修改
- 進入該檔案會顯示衝突位置如下,需手動調整檔案內容
- 修改完後重新 commit,成功解決衝突
如何共同開發專案?#
熟悉 Git 的基本操作後,來談談最一開始提到的多人協作。這些被版本控制的專案,我們稱為「Repository(檔案庫)」,多人協作就是共享同一份 Repository 來完成共同開發。
Git vs GitHub#
Git 是用來版本控制的程式。
GitHub 是目前全球最大的 Git Server,有許多開放原始碼的專案都是使用 Github 進行程式碼的管理。可以想成「提供存放使用 Git 專案倉庫(Repository) 的服務」。也可以不用 GitHub 選擇其他服務,或是自己架一個 Git Sever。
GitHub:視覺化的 repository#
透過 GitHub 的 GUI 介面能夠視覺化 repository,如此就可以在 repository 頁面查看該專案的 Commit 紀錄、檔案修改的歷史紀錄、修改者是誰等資訊,也可在 GitHub 執行 pull request 來進行合併。
建立新專案#
將本地端資料推上遠端 GitHub(Local→Remote)#
建立好新專案後,可分兩種方式開始專案:
- 開始全新專案,再同步到 GitHub
- 已存在專案,將本地端的現存專案同步到 GitHub
git remote
:主要是跟遠端有關的操作#
git remote add origin https://github.com/heidiliu2020/git101_test.git
代表加入遠端節點。也就是「為本地端檔案庫增加一個叫做 origin 的遠端檔案庫」。- 這裡的
origin
是遠端檔案庫的代名詞,代表後面那串 GitHub 伺服器位置。如果從 Server 上 clone 下來,origin 是預設的遠端節點名稱。
git push
:把本地資料同步到遠端#
git push -u origin <branchName>
:將本地端分支資料推到遠端分支git push -u origin master
:將本地端檔案庫推到遠端檔案庫的 master 分支
將遠端資料拉回本地端(Remote→Local)#
git pull
:把遠端資料同步到本地端#
git pull origin <branchName>
:將遠端分支資料拉回並合併本地端分支
從 GitHub Repository 複製專案#
上面介紹的 Push 及 Pull 均使用於本地端現有的專案。
git clone
:從 GitHub 下載 Repository 到本地端#
- 在 GitHub 點選
Clone or download
,可直接下載檔案
- 或是複製網址,到 Terminal 輸入
git clone <網址>
:可將內容下載到本地端
但要注意使用 Clone 的 Repository 沒有權限修改,也就無法再 push 回遠端。
Fork
:將別人的 Repository 複製一份成為自己的 Repository#
- 到想要複製的 Repository 頁面,點選
Fork
- 即可複製一份 Repository 到自己的帳號底下
- 把專案 clone 到本地端,開新的 branch 進行修改
- Push 回自己的專案
- 若為多人協作,可在自己的頁面提出 PR(pull request)給原作
- 若原作同意修改內容,就會在他的頁面按下「Merge pull request」合併 commit
補充:如何在 GitHub 上同步 Fork 過來的 Repository#
git remote -v
:查看目前的遠端節點。只有最一開始設的 origin 這個節點。
git remote add <節點名稱> <網址>
:新增一個遠端節點。
git remote add upstream https://github.com/Lidemy/mentor-program-4th.git
:為本地端檔案庫增加一個叫做upstream
的遠端檔案庫。
git pull upstream master
:把遠端 Repo 同步回本地端電腦。若發生衝突,則手動修改解決。
- 修改完成後,使用
git commit -am "同步課綱 repo"
重新 commit。 git push origin master
:同步回自己在 GitHub 的 遠端 Repo。
若要刪除舊有的 remote,可參考 [Git 筆記] 如何移除 remote origin。
想請問同步課綱 Repo,是不是就和「同步之前 Fork 過來的 Repo」情況相同呢?
git remote add
新增課綱 Repo 這個遠端節點git pull
把新課綱 Repo 同步到本地端,若發生衝突則手動解決再commit
git push
同步回自己在 GitHub 的遠端 Repo
自己依照這些步驟有成功把課綱 Repo 同步到 GitHub,想確認看看這觀念正不正確@@
常見狀況劇:#
commit message 送出後,發現打錯字了想要修改#
git commit --amend
:進入 vim 編輯器,即可修改 commit message。但這個方法只能修改最後一次的 commit message
- vim 編輯器介面如下,編輯完成後回到普通模式,輸入
:wq
存檔退出
git rebase
:可以修改更之前的 commit message,可參考詳細操作流程
補充:若是在已經 commit 而且又 push 的情形下,在本地端進行修改 commit message 可能會造成其他人的困擾。最好的方法還是 push 之前先檢查一下,避免錯的東西被放到遠端。
我 commit 了可是我又不想 commit 了#
git reset HEAD^
:回到上一個 commit 的狀態,保留檔案變更,需要再 commit 來新增版本。預設是 --mixed,可參考 Git reset 的三種模式( soft mixed hard )比較。
HEAD
代表最新的,^
代表前一個。- 因此
HEAD^
就是最新 commit 的前一個狀態,也就是上一個 commit 的狀態。
我還沒 commit,但我想把檔案回復到上次 commit 的狀態#
git checkout -- <file>
:把檔案回復到上一次 commit 的狀態git checkout -- .
:把專案內的所有檔案都回復
- 也可使用
git restore <file>
,和git checkout -- <file>
作用相同。
改 branch 的名稱#
git branch -m feature
:將分支名稱改成 feature。
GitHub Flow#
GitHub 建議管理專案的流程:官網說明
當參與多人開發時:(圖片出自 arccwiki)
- 先 Fork 專案到自己的 repository,開新的 branch 進行開發
- 修改內容後 commit 新增版本,再 push 回自己的 repository
- pull request 到原本專案的 repository 請求合併
- 在上面進行討論,等待對方的 code review
- 在合併前進行最終測試
- 合併成功,刪掉 branch
實戰演練#
假設今天已經建立好本地端和遠端的 resposity,那要如何進行往後的更新呢?
- 新建一個 branch:
git branch joke_1
- 切換到該 branch:
git checkout joke_1
- 編輯檔案
笑話大全.txt
- 完成後,若有新增檔案,可使用
git add .
把檔案加入版本控制 - 進行 commit:
git commit -am “new joke”
- push 本地端分支回遠端 GitHub:
git push origin joke_1
- 到 Github 查看 branch 頁面,提出 PR(pull request)
- 完成合併到遠端 master,即可刪除分支 joke_1
- 把 GitHub 更新的 master 同步到本地端:
git push origin master
- 回到本地端,使用
git branch -d joke_1
刪除分支,結束!
客製化各個階段:Git hook#
用途是「當發生某事的時候通知我」。例如:當有人 commit、有人 push 時通知我。
通常使用在 commit 或是 push 之前,用來檢查程式碼是否符合規範、是否改到不能更改的檔案、是否有放一些不該放的檔案或帳號密碼。
補充:本地端與遠端 - 相關指令#
- 以下示意圖出自此處
參考資料: