Git 學習筆記

這篇是初學 Git 時期草率寫下的筆記,主要目的是幫助自己能快速查找指令。


環境安裝

在進入正題之前,必須先根據電腦的作業系統安裝 Git 的環境,安裝成功後在 Git 資料夾中會有 “Git Bash” 的應用程式,可以透過它來操作 Git 指令;或是使用自己習慣的終端機也可以。

終端機基本指令

使用 Git 時,通常還會搭配一些終端機的基本指令去輔助操作,常用的指令如下:

移動到指定目錄

指令:cd 資料夾路徑

除了直接輸入路徑,也可以直接將資料夾拖曳至終端機視窗中。

展開當前目錄

指令:ls

列出當前目錄的所有檔案。

回前一層目錄

指令:cd ..

從當前位置回到前一層目錄。

回到根目錄

指令:cd\

直接移動到根目錄。

新增資料夾

指令:mkdir 資料夾名稱

在當前目錄下建立一個資料夾。

新增檔案

指令:touch 檔案名稱.檔案類型

在當前目錄建立一個檔案。

刪除檔案

指令:rm 檔案名稱.檔案類型

刪除當前目錄中指定檔案,若要刪除指定資料夾(含內容所有檔案)可輸入 rm -r 資料夾名稱

Git 版本檢視

環境安裝完成後開啟終端機,嘗試輸入指令 $ git version ,如果若出現 Git 版本訊息即表示安裝成功。

版本訊息範例:

1
2
$ git version
git version 2.32.0.windows.2

Git 環境設定

使用 Git 進行版本控制時,每一個更新紀錄的更新人、更新時間以及部分的內容都會被記錄;因此在開始使用 Git 之前,需要先設定一些基本的資訊。

設定使用者暱稱

指令:$ git config --global user.name "使用者暱稱"

設定使用者信箱

指令:$ git config --global user.email "使用者信箱"

查看設定值

指令:$ git config --list

Git 常用指令

Git 基本操作流程示意圖:

Git 操作方式會根據不同情境而有所差異,但是運作原理相同。

建立本地端儲存庫

指令:$ git init

儲存庫(Repositiory)是用來存放一個專案所有檔案的資料夾;建立方式只需要開啟終端機,並以任意資料夾作為根目錄並輸入上述指令即可。

以檔名為 Project 的資料夾為例,建立成功後會顯示以下訊息:

1
2
$ git init
Initialized empty Git repository in C:/Users/user/Desktop/Project/.git/

此外也可以開啟該資料夾,查看根目錄是否多出一個 .git 的資料夾,它主要是用於監控與紀錄資料夾內檔案的所有變動;通常 .git 資料夾預設會隱藏,可以從資料夾上方列的 “檢視” 開啟隱藏的項目。

檢視狀態

指令:$ git status

查看工作目錄與暫存區的檔案是否有變動;可得知哪些檔案被修改,哪些檔案尚未被 Git 追蹤。

以 Project(本地端儲存庫)為例,輸入指令時顯示以下訊息,表示尚未做任何檔案新增或編輯:

1
2
3
4
$ git status
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)

加入暫存區

指令:$ git add .

工作目錄有新增或編輯的檔案時,可以輸入上述指令將檔案加入暫存區(索引),並等待提交成一次新的版本。

新增檔案 index.html 在 Project 資料夾中,並輸入指令 $ git status 查看狀態時顯示以下訊息:

1
2
3
4
5
6
7
8
9
$ git status
On branch master

No commits yet
Untracked files: # 偵測到未被追蹤檔案
(use "git add <file>..." to include in what will be committed)
index.html # 檔案名稱

nothing added to commit but untracked files present (use "git add" to track)

訊息顯示偵測到尚未追蹤的檔案 index.html,此時可以輸入上述指令將檔案加入暫存區。

檔案加入暫存區後,輸入 $ git status 查看狀態時顯示以下訊息:

1
2
3
4
5
6
7
$ git status
On branch master

No commits yet
Changes to be committed: # 工作目錄的檔案已被加入暫存區等待提交
(use "git rm --cached <file>..." to unstage)
new file: index.html # 檔案名稱

補充說明:

使用指令 $ git status 查詢狀態時,如果是工作目錄新增的檔案,狀態會是 Untracked files,表示尚未加入暫存區追蹤;但如果是暫存區已存在,後續再進行修改的檔案,狀態會是 Changes not staged for commit,並且檔案前面會標註 modified,表示該檔案已被編輯,需要再次加入暫存區等待提交。

下列為檔案在不同狀態下所表示的意思:

1
2
3
Changes to be committed        # 已加入暫存區,準備提交成一次新的版本紀錄。
Changes not staged for commit # 已被追蹤,但尚未加入至暫存區。
Untracked file # 新建立,尚未被追蹤的檔案。

提交更新(Commit)

指令:$ git commit -m "提交內容敘述"

將暫存區的檔案提交一次新的版本紀錄。

以下為成功提交暫存區的檔案 index.html 後顯示的訊息:

1
2
3
4
$ git commit -m "新增 index"
[master (root-commit) ce9d927] 新增 index # 提交內容敘述
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 index.html # 被提交的檔案

提交暫存區的檔案後,輸入 $ git status 查看狀態時顯示以下訊息,表示沒有更動需要提交,並且目前工作目錄乾淨,完全沒有檔案新增、修改或刪除。

1
2
3
$ git status
On branch master
nothing to commit, working tree clean

查詢提交紀錄

指令:$ git log

列出過去幾筆的提交紀錄。

以下為提交紀錄的顯示內容範例:

1
2
3
4
5
6
$ git log
commit ce9d92723df3302156a9523453c0fff21f7fdcc0 (HEAD -> master)
Author: Cliff Chu <[email protected]>
Date: Sun Jan 23 17:53:08 2022 +0800

新增 index

顯示的筆數較多時,按下鍵盤 q 即可返回原內容。

忽略檔案

不希望某些檔案被 Git 追蹤時,可以建立一個 .gitignore 檔案,透過編輯器開啟檔案後,輸入希望被忽略的檔案名稱和檔案類型並儲存即可;需要注意的是 .gitignore 檔案本身不會被忽略。

被忽略檔案的輸入格式分別為下列幾種類型:

  • 忽略單一檔案:輸入格式:檔案名稱.檔案類型

  • 忽略檔案類型:輸入格式:*.檔案類型

  • 忽略單一資料夾:輸入格式:資料夾名稱/

還原(Reset)

開始介紹 $ git reset 相關指令之前,需要先理解 Reset 會使用到的三種參數模式,如下所示:

  • --mixed(預設模式):暫存區的檔案會被丟回工作目錄,但是原本工作目錄的檔案不會被影響。
  • --soft:移除 commit 節點,但是暫存區與工作目錄的檔案皆不會被影響。
  • --hard:移除 commit 節點、工作目錄與暫存區所有檔案。

補充說明:

^ 符號代表要往回還原的版本次數,HEAD^ 代表往回一個版本,也可以使用 ~ 加上數字來代替 ^ 符號的數目,@ 符號可以用來代表 HEAD;以 HEAD^^ 為例,可以改成 HEAD~2,或 @~2

還原暫存區單一檔案回工作目錄

指令:$ git reset HEAD 檔案名稱

還原暫存區所有檔案回工作目錄

指令:$ git reset HEAD

還原單一檔案內容

指令:$ git checkout 檔案名稱.檔案類型

指定檔案內容還原回最後一次提交的狀態。

還原工作目錄與暫存區

指令:$ git reset --hard

當前工作目錄與暫存區,皆還原回最後一次提交時的狀態。

需要注意空的資料夾本身會被 git 忽略,因此不會被指令還原;但是資料夾內有存在檔案時,就會被 git 追蹤並還原。

移除最新的提交節點

指令:$ git reset HEAD^ --hard

除了移除最新的節點之外,當前暫存區的檔案也會被移除,但是當前工作目錄的檔案不受影響。

還原被移除的最新提交節點

指令:$ git reset ORIG_HEAD --hard

還原指令 $ git reset --hard HEAD^ 移除的節點,並移除當前暫存區的檔案,但是當前工作目錄不受影響。

補充說明:

指令中的 ORIG_HEAD 是當使用者在執行一些較危險的指令(mergerebasereset …)時,當前 HEAD 的檔案狀態會事先存放的地方,隨時可以還原。

除了上述方法,也可以使用以下指令來還原狀態:

1
$ git reset 89cb75  # 指令中的亂數為被刪除節點的 SHA-1 值

需要注意被刪除的節點無法透過 $ git log 來查詢,查詢的方式可以使用指令 $ git reflog 來檢視歷史的狀態紀錄。

移除最新的提交節點並保留檔案狀態

指令:$ git reset HEAD^ --soft

可以理解成沒有執行最後一次的提交動作。

修改最新提交節點的描述

指令:$ git commit --amend -m "修改描述"

修改當前分支最新一次的提交描述。

追加檔案到最新的提交節點

指令:$ git commit --amend --no-edit

執行指令時如果未加上 --no-edit 參數,會跳出 Vim 編輯視窗。

分支

分支(branch)是開發者在團隊協作一個專案時,會需要使用到的 Git 架構內容;可以理解成將當前儲存庫的所有檔案複製一份,而這兩個版本可以獨立進行檔案新增、編輯與修改。這樣的好處是檔案的內容如果需要做更動,就可以先移動到另一個分支動作,同時也不用擔心影響到原本的檔案狀態。

以下列出常見分支名稱與主要用途:

  • master(預設分支):用來合併 develop,合併時才會產生提交節點。
  • develop(開發分支):用來合併 feature 分支,合併時才會產生提交節點。
  • feature:用來開發功能、修改錯誤。

進入分支之前,需要先對 HEAD 指標有些概念,可以把它理解成當前分支上的所在位置;資料夾路徑可以看到目前 HEAD 的指向,如下圖所示:

1
user@DESKTOP-LV1TU83 MINGW64 ~/Desktop/Project (master)  # 目前 HEAD 正指向 master 分支

檢視當前所有分支

指令:$ git branch

查詢目前本地端儲存庫的所有分支。

以 Project(本地端儲存庫)為例,輸入指令後顯示以下訊息,表示目前本地端有兩個分支,分別為 develop 與 master,而符號 * 表示當前 HEAD 正指向的分支。

1
2
3
$ git branch
develop
* master

移動 HEAD 到指定提交節點

指令:$ git checkout SHA-1前4碼

用來查看某一次的 commit 內容;而 SHA-1 值可透過 $ git log 查詢,如下所示:

1
2
3
4
5
commit ce9d92723df3302156a9523453c0fff21f7fdcc0
Author: Cliff Chu <[email protected]>
Date: Sun Jan 23 17:53:08 2022 +0800

新增 index

接著輸入指令 $ git checkout ce9d 就能夠移動 HEAD 到這次 commit 節點,如果要回到原本位置,只需要輸入 $ git checkout 當前分支名稱 即可。

建立分支

指令:$ git branch 分支名稱

建立一個新的分支,但是 HEAD 的指向不變。

切換當前分支

指令:$ git checkout 分支名稱

移動 HEAD 到指定分支的最後一次提交節點。

合併分支 - 快轉模式(Fast-Forward)

指令:$ git merge 合併的分支名稱

快轉模式下,兩分支合併後路線重疊,並且不會產生額外的提交節點。

兩分支合併之前,如果最後提交節點都在同一個位置,合併時就會產生快轉模式(Fast - Forward),如下圖所示:

已知合併前的圖中,feature 分支比 master 分支多了兩次提交節點,但是 master 並沒有新增自己的節點,所以 master 分支的檔案在 feature 分支也都有,可以理解成 feature 分支只是 master 分支未來的版本而已,因此進行合併後,master 分支與 feature 分支會重疊,並且不會產生額外的合併節點,這種合併模式稱為 “快轉模式(Fast - Forward)”。

合併分支 - 關閉快轉模式

指令:$ git merge 合併的分支名稱 –no-ff

非快轉模式下,兩分支合併後會產生額外的提交節點。

下圖為加上參數 --no-ff 關閉快轉模式的例子:

圖中合併前的狀態前面的案例相同,因此在正常情況下合併兩分支就會產生快轉模式;但是也可以在合併時加上參數 --no-ff 來關閉快轉模式,如此一來,兩分支在合併後不但不會重疊,並且會額外產生新的提交節點。

補充說明:

兩分支在非快轉模式下進行合併時,可能會跳出以下訊息,表示需要輸入合併的原因;此時可以按下 i 進入輸入模式,接著將黃色文字的部分改成合併的簡單敘述(同 commit 訊息),輸入完畢後再按下 Esc 退出輸入模式,最後在底部輸入 :wq 即可完成合併並回到原來的畫面。

將當前分支合併到指定分支前

指令: $ git rebase 要合併的分支名稱

複製當前分支所有的提交節點,合併在指定的分支前面。

需要注意複製的提交節點會重新產生個別的 SHA-1,與原先的節點彼此並不相同,而原先的節點會隨著時間被 Git 機制回收。

補充說明:

使用 rebase 合併後,無法透過 $ git reset HEAD^ 還原回合併前的狀態,而是會還原到前一個節點上;如果要還原回合併前的狀態,可以使用指令 $ git reset ORIG_HEAD --hard

下列圖片為兩分支在使用 rebase 合併時,可能產生的衝突:

合併時顯示上述訊息,表示檔案內容有衝突,此時可以開啟編輯器查看衝突的部分,以下圖為例:

確認完衝突的檔案內容後,只需要在終端機再次將檔案加入暫存區,接著輸入以下指令再次嘗試合併即可。

1
$ git rebase --continue

指定提交節點合併到當前分支前

指令: $ git cherry-pick SHA-1 SHA-1

複製指定的單一或數個提交節點,合併在當前分支前面。

以下圖為例,嘗試將 feature 分支的 add style 與 add js 兩個合併節點,合併在 master 分支前面:

可以從 sourcetree 介面中的右側看到每個節點的 SHA-1,在取得 add style 與 add js 兩個節點的值後,在 master 分支執行以下指令,即可複製被指定的兩個節點,並合併在當前分支前面。

1
$ git cherry-pick 7316ad7 3372681

如果希望被複製過來的節點不要直接進行合併,可以在指令後方加上參數 --no-commit,如下所示:

1
$ git cherry-pick 7316ad7 3372681 --no-commit

此時被複製過來的節點會被拆除,並將節點的檔案加入暫存區,也可以透過 $ git status 查詢狀態,會發現暫存區目前有兩個檔案等待提交,如下所示:

1
2
3
4
5
6
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: all.js
new file: style.css

確認檔案沒問題後,就可以進行提交,結果如下圖所示:

標籤(Tag)

開發專案過程中,會因為檔案不斷新增、刪除或修改而增加許多提交節點,雖然彼此都有獨自的版本描述,但是這樣很難去區分彼此之間的重要程度,如不同時間點的上線版本;因此為了有效區別,可以使用標籤相關指令。

補充說明:

標籤和分支都是指向某一個提交節點的指標,但是兩者的差別在於標籤只會指向固定的提交節點,而分支會隨著提交的增加而移動到最新的節點。

新增標籤

指令:$ git tag 標籤名稱

在當前位置新增一個標籤,可使用指令 $ git tag 來查詢標籤。

新增標示標籤

指令:$ git tag -am "標示內容" 標籤名稱

在當前位置新增一個標籤,並加入詳細的敘述,可以使用指令 $ git tag -n 來檢視標籤的詳細內容。

刪除標籤

指令:$ git tag -d 標籤名稱

可以將標籤想像成一張貼紙,撕掉並不會影響提交的檔案狀態。

移動到指定標籤位置

指令:$ git checkout 標籤名稱

移動 HEAD 的位置到指定標籤上查看檔案狀態,輸入 $ git checkout 分支名稱 即可回到原本內容。

暫存(Stash)

團隊開發專案的過程中,常常會開發到一半出現突發狀況要處理,其中一種作法是,先將目前的工作內容加入暫存區並提交,解決突發狀況後,再透過指令 $ git reset --soft HEAD^ 刪除最後一次的提交節點,並還原提交前的所有狀態;另外一種做法則是透過 $ git stash 相關指令來暫存檔案狀態。

補充說明:

暫存(stash)和暫存區(Staging Area)兩者屬於不同的概念。

暫存當前的檔案狀態

指令:$ git stash

暫存當前工作目錄已被追蹤與暫存區(Staging Area)的檔案狀態,暫存後無法透過 $ git status 查詢檔案。

檢視暫存列表

指令:$ git stash list

透過指令 $ git stash 暫存的檔案可以使用上述指令來查詢,以下為查詢結果範例:

1
2
$ git stash list
stash@{0}: WIP on master: 15988d5 add index

還原暫存的檔案狀態

指令:$ git stash pop

將暫存的檔案狀態還原到當前分支上,有搬運檔案的功能。

清除最新暫存

指令:$ git stash drop

刪除暫存列表最新的暫存紀錄,並無法還原。

清除全部暫存

指令:$ git stash clear

刪除暫存列表所有的暫存紀錄,並無法還原。

遠端儲存庫操作指令

本篇內容主要是在著重講述 Git 的基本操作,因此先不討論遠端儲存庫的建立方式與相關內容。

連結遠端儲存庫

指令:$ git remote add origin 遠端儲存庫網址

指令中的 origin 為遠端儲存庫的預設名稱;實務上通常會有多個儲存庫,如正式主機與測試主機;使用者可根據儲存庫用途來自訂名稱。

查詢遠端儲存庫

指令:$ git remote

查詢與本地端連結的遠端儲存庫的名稱;加入參數 -v 可以查詢詳細名稱與路徑。

複製遠端儲存庫

指令:$ git clone 遠端儲存庫網址

複製遠端資料到本地端資料夾,並建立工作目錄與本地端儲存庫(.git 資料夾),在指令後方加上 -b 遠端分支名稱 可以指定要複製的遠端分支。

補充說明:

上述指令通常會在本地端尚未存在遠端的資料的形況下執行;而後續本地端的資料更新都是透過 $ git pull 相關指令來操作。

推送本地端分支到遠端分支

指令:$ git push 遠端儲存庫名稱 遠端分支名稱

與本地端連結的遠端儲存庫如果有一個以上,在推送的時候要注意遠端儲存庫名稱,是否與要推送的遠端儲存庫相同,避免推送到錯誤的遠端。

補充說明:

第一次在推送時,如果在指令中加入參數 -u,Git 就會記錄這次的推送行為,後續在推送本地端資料回遠端時,只需要輸入指令 $ git push 即可,但是也會遇到無法推送的情形,這部分會在 $ git pull 的部分說明。

1
$ git push -u 遠端儲存庫名稱 遠端分支名稱

變更遠端儲存庫名稱

指令:$ git remote rename 原儲存庫名稱 修改後名稱

預設的遠端儲存庫名稱為 origin

複製遠端儲存庫分支與本地端分支合併

指令:$ git pull 遠端儲存庫名稱 遠端分支名稱

團隊協作開發專案時,因為每個人的進度不同,會需要不定時更新遠端的資料回本地端;與 $ git clone 不同的是,$ git pull 是使用在本地端已經存在遠端的資料,但是需要更新檔案進度時。

推送本地端資料回遠端前,如果遠端資料已更新,本地端在推送時就會出現以下衝突訊息:

此時需要使用 $ git pull 先將遠端最新的資料更新(複製)到本地端,在複製遠端資料時會跳出以下訊息,表示需要將遠端資料與本地端進行合併。

從上述行為可得知,指令 $ git pull 做的事情是將遠端分支複製一份到本地端,再直接進行合併的動作。

複製遠端儲存庫分支與本地端分支等待合併

指令:$ git fetch 遠端儲存庫名稱 遠端分支名稱

$ git pull 不同的是,使用 $ git fetch 取得的遠端最新檔案會產生一個 FETCH_HEAD,表示遠端分支的最新狀態 遠端儲存庫名稱/遠端儲存庫分支遠端儲存庫名稱/HEAD,並額外產生提交節點在本地端當前分支前面,使用者檢查後再決定是否要與本地端分支合併,合併指令如下:

1
$ git merge 遠端儲存庫名稱/遠端儲存庫分支

從上述行為可得知,$ git pull 做的動作相當於 $ git fetch 加上 $ git merge

參考資料

如何使用 –amend 追加檔案
Fast-Forward 快轉模式詳細介紹
Git Stash 詳細使用方式
Git Reset 使用模式
使用 Git Rebase 合併
Git Fetch 詳細介紹


Git 學習筆記
http://kurifu.tw/2022-01-20-git-note/
作者
Cliff Chu
發布於
2022年1月20日
許可協議