①②⓪Git 版本控制入門(2)

Beginning Git: Ep. 5 ~ 6,Committing Changes,The Staging Area

Min
15 min readJan 8, 2024

接續上一篇:

線上課程資源:

以下跟著課程實做用 zsh 練習 git:

Ep. 5 Committing Changes

每個 Commit 可以有一或兩個 parents,以只有一個 parent 的 Commit 為例,從 parent 過渡到 child 的內容稱為 DIFF。DIFF 紀錄著 parent 與 child 的不同,在創造 Commit 的當下,跟上一個 Commit 有什麼改變。

到上次 clone 下來的 rwTODOs 中,打開 books_ideas.md 增加內容:

在最後一行加上新書 idea:

儲存並退出

接著使用 git status 查詢目前的狀態,看到剛剛做的修改已經記錄下來,但還沒加入暫存區(stage it)。如果現在 commit,這個檔案的更改不會被提交。

使用 git diff 看實際改變的檔案內容:

git diff

使用 git add . 將當前 directory 與 subdirectories 的變化加入暫存:

git add .

再次使用git status 查詢目前的狀態,看到剛剛的改變已經 stage 了:

接著輸入 git commit 將進入文字編輯模式:

git commit

Commit 的第一行文字是這個 commit 訊息的標題,與這次改變的總結。通常要有一定的字數長度。空一行後在第三行寫下任何與這次 Commit 相關的細節:

儲存後退出

再次輸入 git commit ,可以看到 working tree 已經 clean,也就是說目前沒有任何修改過的檔案了:

輸入 git log 可以看到剛剛 Commit 的資訊與文字:

輸入 git log -p ,顯示出每個 Commit 之間的 DIFF:

git log -p

創建一個名為“tutorials” 的 Directory:

mkdir tutorials

使用git status 查詢目前的狀態,發現新的 Directory 還沒被 registering(註冊/紀錄,被 Git 追蹤):

為什麼會這樣呢?因為 Git 只追蹤檔案,但它跟資料夾不熟。Git 很懂檔案沒錯,包含路徑與內容,但只能透過每個存取檔案的路徑去釐清一個資料夾的結構。

因此,如果想在 Git 中建立一個空的 directory,沒門!一定無法是空的,必須在裡面放一個隱藏的檔案,通常是 .keep 或 .gitkeep。

透過在想建立的 tutorials 資料夾內再放一個 .keep 檔,讓 Git 看到新資料夾:

touch tutorials/.keep

使用git status 查詢目前的狀態,出現了一個 untracked file:

使用 git add . 將當前的變化加入暫存,接著使用 git commit -m 不打開文字編輯模式直接留下 Commit 的文字:

git commit -m "標題文字"

使用git status 查詢目前的狀態,目前的 working tree 已清空。

輸入 git log 查看剛剛新增的 Commit:

練習時間

在 Tutorial Directory 中,創建一個新的 Markdown File。將關於藝術與手工藝的想法寫進去。接著 Commit。

vim tutorials/artsAndCrafts.md

使用git status 查詢目前的狀態:

使用 git add tutorials/* 將 tutorial 資料夾內的所有檔案 staged:

git add tutorials/*

使用 git commit -m "標題名稱" 完成 Commit:

輸入 git log 查看剛剛新增的 Commit:

輸入 git log -p 看 所有 DIFF,包括最新的:

Ep. 5 重點 git 指令

git status      查詢目前的狀態
git diff 查看改變的檔案內容
git add . 將當前 directory 加入暫存,staged
git commit 進入文字編輯模式編輯 commit 內容
git commit -m 不打開文字編輯模式直接 Commit
git log 看先前 Commit 的資訊與文字
git log -p 顯示每個 Commit 之間的 DIFF
touch tutorials/.keep 利用隱藏檔名新增可被 Git 看見的資料夾
git add tutorials/* 將 tutorial 資料夾內的所有檔案 staged

Ep. 6 The Staging Area

這章將研究什麼是 Staging Area,以及 git add 又是在做什麼?

Git 的概念中,有三個領域:

  • Working Directory(工作區): 指目前正在工作的目錄,使用者在不同的 commit 中瀏覽與編輯檔案,Git 則用來追蹤並管理這些文件的變更和狀態。
  • Staging Area(暫存區,又稱為 Index):通常我們用 git add 將下一個 commit 先存在 Staging Area,再輸入 git commit 時存進 repository。在 Staging Area 中可以選擇哪些變更 commit 就好,不用全部 commit 到 repo 中。
  • Repo(Repository):所有 commits 的資料庫。

以下實做將原本的專案分成兩個 commit,展示如何利用最終 commit 之前的 git add。

vim 打開 book_ideas.md

vim books/book_ideas.md

在 vim 模式中,於空格處輸入 rx 會將空格替換成 x:

CVS 那行打叉後,到最後一行按下 o 新增一行。加上另一個點子“50 Shades of Green”:

:wq 儲存並離開

輸入 git status 會看到剛剛對 book_ideas.md 檔案做了更動:

git diff 顯示變動的那兩行:

git add . 將此變動加入 Staging Area,再用 git status看到已將之 stage 了:

這時輸入 git diff 不會出現任何東西,因為 Working Directory 跟 Staging Area 內的檔案沒有任何差異。

使用git diff --staged 查看 stage area 內的東西與最後一次 commit 時的差異:

git diff --staged

使用 git reset HEAD取消已經暫存的變更,把檔案放回 Working Directory:

git reset HEAD books/book_ideas.md

用 git status 檢查,果然回到沒被 stage 的狀態:

使用 interactive adding,git add -i,來規劃哪些東西想要 stage。

git add -i

在最前方可以看到目前已經修改但還沒被 stage 的部分,目前 book_ideas.md 都還沒 stage ,包含兩個增加、兩個刪除:

下方是指令列,顯示目前可進行的選項

輸入 s ,看目前的狀態,就跟上圖一樣:

輸入u,update,可以 stage 檔案,顯示所有可 stage 的檔案,使用者可以選擇:

輸入 b 以選擇 books:

此時按下 enter 將 books staged 並返回 main menu,按下 s 確認狀態,看到目前整個 books 檔案都 stage 了,沒東西可以再 stage:

接著再 unstage,使用 revert 指令,輸入 r,再選擇 b 之後按下 enter:

用 s 檢查,發現那些更動又變回 unstaged:

patch 指令可以選擇每個檔案的 subsections(子節),輸入 p 之後也再選擇 b:

按下 enter 之後離開 patch menu 並帶你完成每個變動的 patch:

hunk 是一塊塊檔案中有修改的部分,這裡輸入 s 以 split 整個 hunk,先出現的是分裂出來的第一個 hunk,是 CVS 那一行:

手殘多按了一個 s 也沒關係

輸入 y 表示同意 stage 這行 hunk,接著出現第二個 hunk,是 50 Shandes of Green:

不想 stage 它,因此輸入 n。之後回到 main menu:

按 s 確認狀態,目前 staged 跟 unstaged 各是 +1/-1:

按 d 去看已經 stage 的部分的 DIFF:

再按 b 選擇 books,的確是 CVS 這行的異動:

按 q 離開 interactive add tool:

竟然會道別QQ

git status 顯示有 staged 跟沒有 staged 的檔案:

git diff 顯示沒 stage 的部分:

git diff --staged 顯示 stage 的改變:

git commit -m “Completed the CVS book” commit :

git status 則看到還沒 stage 的部分,已經 commit 的部分就消失了:

git log -p 查看之前的 commit,只有 CVS 的改變:

patch add 的捷徑:

git add -p

使用 git add -p 再次把檔案 split 成 hunks,不過只剩下一個 hunk 了:

選擇 y 以 stage,git commit -m “Adding the new book ideas” 以 commit:

git log 檢查剛剛的 commit:

輸入 git log -p ,顯示每個 Commit 間的 DIFF:

練習時間

將 articles/ios_article_ideas.md 移動到 tutorials 資料夾中,並刪除 videos/live_streaming_ideas.md。

使用 mv 移動檔案:

mv articles/ios_article_ideas.md tutorials

此時的 git status

目前刪除和新增都沒被 Git 追蹤到,因為它不懂移動。

透過 git add .git status 調查發現,原來 Git 把移動當成是我們把檔案重新命名(renamed)了。表示對 Git 來說,只是檔案的路徑名稱更改:

因此,我們得先還原剛剛做的所有動作。先用 git reset HEAD . unstaged:

git reset HEAD .
. 代表當前目錄

git status 檢查:

再來,撤銷剛剛的刪除:

git checkout -- .

git status 檢查:

刪掉新增的部分:

rm tutorials/ios_article_ideas.md

git status 檢查:

終於回到原點

真正能讓 Git 理解檔案是被移動的,要在 mv 前加上 git

git mv articles/ios_article_ideas.md tutorials 

git status 檢查:

git commit -m 提交變更:

git rm 不僅能刪除檔案,還會更新 Git index,直接變成 staged:

git rm videos/live_streaming_ideas.md

git status 檢查:

git commit -m “Removing the live streaming ideas” 提交變更:

git status 檢查:

git log -p 呈現刪除檔案的 DIFF:

Ep. 6 重點 git 指令

git diff --staged 查看 stage area 內的東西與最後一次 commit 時的差異
git reset HEAD 取消已經暫存的變更,把檔案放回 Working Directory
git add -i 使用 interactive adding

interactive adding
1. status 查詢目前狀態,包括哪些檔案已經被修改、暫存(staged)或未追蹤(untracked)。
2. update 列出所有已修改但尚未暫存的檔案。使用者可以選擇從這些檔案中暫存(stage)哪些檔案。
3. revert unstage,將已經暫存的變更取消暫存。這對於撤銷之前的暫存操作很有用。
4. add untracked 允許將新的未追蹤檔案(即那些尚未被 Git 追蹤的檔案)添加到暫存區。
5. patch 允許選擇一個文件中的特定變更來暫存。這是一種精確控制暫存變更的方法,特別有用於當只想提交一部分變更。
6. diff 顯示已經暫存和尚未暫存的變更之間的差異。這有助於確認哪些變更即將被提交。
7. quit 退出interactive adding 模式,不進行任何未保存的暫存操作。
8. help 顯示interactive adding 模式的幫助資訊,包括所有可用命令的說明。

在 patch 中針對 hunk 的操作:
* y:暫存這個 hunk。
* n:不暫存這個 hunk。
* q:退出 patch 模式,不再查看更多的 hunk。
* a:暫存這個 hunk 並自動暫存所有剩餘的 hunk。
* d:不暫存這個 hunk 並忽略所有剩餘的 hunk。
* e:手動編輯當前的 hunk。
* ?:顯示所有選項的說明。

git add -p patch add 的捷徑,可選擇只 commit 修復相關的變更
git checkout -- . 撤銷當前目錄下所有未暫存(unstaged)的變更

mv 移動檔案
git mv 可被 Git 識別的移動檔案
git rm 不僅刪除了文件,還會更新 Git index

謝謝收看,下次將往 Ignoring Files 跟 Viewing History 前進:

--

--