# 前言

上一篇文章,我們已經學會使用 git status 來查看檔案狀態,不過 git status 呈現的檔案狀態,好像不是只有 暫存 (stage) 與 未暫存 (unstage) 這麼簡單。

這篇文章我們來更細部的探討 Git 中,資料會出現的狀態。

預告一下:
文章預計會說明四個名詞定義,最後還會證明其中兩個名詞 未追蹤 等於 未暫存,整篇內容可能會讓新手看完覺得頭很暈!

如果你畏懼字詞解釋的話,可以直接滑到文章最底端,看結論。

# 已追蹤 (Tracked) 、未追蹤 (Untracked),已暫存 (Staged)、未暫存 (Unstaged)

執行 git status 指令時,會發現 Git 將 新增加的檔案 描述成 未追蹤的檔案 (Untracked files)。

可是不對阿…
加入暫存區的檔案叫做 已暫存,那我還沒把檔案加入暫存區,為什麼叫做 未追蹤,不直接叫 未暫存?

在實際開始解釋之前,說明一個可能比較抽象的觀念:
我們說 git add 是把檔案放到暫存區的行為,而這個 暫存區 是真的有這東西,他座落於 .git 資料夾裡面,是一個名叫 index (索引) 的檔案。
Alt text

而「索引」到底是不是真的像購物車一樣,下單後會「清空資料」? 其實 「不是」。

在 Git 中,能在加入索引之後,又移出索引的資料,只有 還沒 commit 過的資料 才能做到。
沒commit 的檔案可以移出索引示意圖

否則,只要 commit 過的檔案,資料永遠會紀錄在 索引 裡面。

檔案進了 Git 就跟得罪方丈一樣,想走沒那麼容易!- 高見龍 (龍哥)《為你自己學 Git》

如果你還沒因為 暫存區 又叫 索引 這件事混淆的話,那我們繼續看下去:

# 未追蹤 (Untracked) 、追蹤 (Tracked) 的定義

  1. 未追蹤的檔案 (Untracked files):所有 不在索引 的檔案。
  2. 已追蹤的檔案 (Tracked files):所有 存在於索引 的檔案。

同時,已追蹤 的檔案,可以再區分成 未暫存 與 暫存:

# 未暫存 (Unstaged)、暫存 (Staged) 的定義

  1. 未暫存的檔案 (Unstaged files):索引的內容 與 工作目錄的內容 不一致 的檔案
  2. 已暫存的檔案 (Staged files):索引的內容 與 作目錄的內容 一致 的檔案

了解定義之後,我們可以回頭來看工作目錄中,可能會有的檔案狀態:

# 工作目錄可能會出現的檔案狀態整理

在工作目錄中操作檔案,以及執行會更動索引資料的指令 (註 1) 時,都會使檔案狀態發生變化。

下文整理 (註 2) 一下我們在開發與版控時,工作目錄的檔案可能會出現的狀態,這裡更動索引資料的指令,以最常使用的 git add 為例:

  1. 執行 git add 之前:
  • 新增檔案 (尚未列入追蹤的檔案) :未追蹤
  1. 執行 git add 之後:
  • 新增檔案 (已經加入索引的檔案) :已追蹤 / 暫存
  • 修改檔案 (已經加入索引的檔案) :已追蹤 / 暫存
  • 刪除檔案 (已經加入索引的檔案) :已追蹤 / 暫存
  1. 執行 git commit 之後又進行異動:
  • 修改檔案 (尚未加入索引的檔案) :已追蹤 / 未暫存
  • 刪除檔案 (尚未加入索引的檔案) :已追蹤 / 未暫存

用上面列的這三種區域來看的話,當檔案被 commit 過後,編輯這些檔案再 commit 一版的行為,就是不停的讓檔案在 第三區 與 第二區 的狀態不斷循環。

註 1. 在 Git 中,並不只有 git add 與 git commit 兩個指令會影響到檔案狀態,舉凡一切會去異動索引資料的指令,都會影響檔案在 Git 中的狀態,例如 reset 、 rebase 等。

註 2. 原始資料整理自保哥的文章。

# 常見問題

# 「未追蹤」的檔案算不算「未暫存」的檔案?

廣義來說,算。

記得 Fork GUI 介面中,工作目錄剛新增的那些 未追蹤檔案 出現的位置在哪嗎?

沒錯,竟然是未暫存區 (Unstaged)!

如果你已經忘記了,我附個圖:
暫存,未暫存示意圖
(p.s. 朋友希望 Fork 的畫面能跟背景色有對比,預計之後都會以深色系來截圖)

再列一次兩個名詞的定義:

  • 「未追蹤」檔案:尚未紀錄到索引 的檔案。
  • 「未暫存」檔案:索引 與 工作目錄 資料「 不一致 」 的檔案。

有了定義,我們就可以來證明這兩者是不是相同的意思。

試證明: 「未追蹤」 檔案等於 「未暫存」 檔案:

  1. 因為 「未追蹤」 檔案是 「尚未紀錄到索引」 的檔案,所以 「索引」 不會有 「未追蹤」 的資料。
  2. 雖然 「索引」 沒有 「未追蹤」 檔案,但如果出現 「未追蹤」 的檔案,表示工作目錄有檔案。
  3. 由第二點推論出 「未追蹤」 的檔案在 「索引與工作目錄」 兩個位置的資料 「不一致」 。
  4. 由於 「索引與工作目錄」 記錄的資料 「不一致」 的檔案,稱為 「未暫存」 的檔案。

得證: 「未追蹤」 檔案等於 「未暫存」 檔案。

# 總結

我們在使用 Git 版控,都是持續更改檔案狀態的行為,了解 Git 對檔案狀態的分類,可以在未來面對不同情境時,知道下一步該如何操作,不會手忙腳亂。

如果因為這篇文章的各種狀態,以及看完證明題後搞得頭暈腦脹, 然後不想再跟我這種數學系的人說話 ,在初學 Git 的階段,先記得一件事情就好:

要執行 commit 之前,通通先 add 過吧!