[檔案管理] git 教學:紀錄--查看提交的歷史 - 精華區

[檔案管理] git 教學:紀錄--查看提交的歷史

阿慶

阿慶圖像

2020-03-24 23:25:33

From:122.116.71.150

基本款

之前我們已經做了幾次 commit 的提交,那我們應該怎麼查看這些紀錄呢?指令是 git log

$ git log
 commit 462682ddf12ddebd3e7b4c6796ffb0907560f08b (HEAD -> master)
 Author: Logo Kuo <logo@forblind.org.tw>
 Date:   Sun Feb 16 13:34:36 2020 +0800

     沒東西

 commit 0fdb52fe4c91c1f2b342922ea031ab63c6d1078f
 Author: Logo Kuo <logo@forblind.org.tw>
 Date:   Sun Feb 16 13:01:25 2020 +0800

     加入git並新增welcome.txt檔案

我後來有把 user.name 跟 user.email 改過,所以這邊的紀錄不是 nvda

從上面的資訊可以看出我們目前有兩個提交:

  1. 越新的資訊會在越上面
  2. 是誰在什麼時候 commit 的
  3. commit 的內容是什麼

至於在每個 commit 後面的那串像亂碼的字串是什麼?462682ddf12ddebd3e7b4c6796ffb0907560f08b

那是使用 sha1 演算法產生出來的每個提交代號,它的重複率非常非常低,所以我們可以把它當作是每個版本的代號。

在 git 當中就是認這個代號,像是我們要切換到不同的 commit 狀態就要靠這些代號,這也就是所謂的版本號了。

而在最上面的 commit 後面有個 (HEAD -> master) 是告訴我們目前正處在這個 commit 版本狀態中。

master 是預設的主分支,這部分我們之後再說。

另外,git log 可以有一些參數,例如 --oneline

$ git log --oneline
 462682d (HEAD -> master) 沒東西
 0fdb52f 加入git並新增welcome.txt檔案

這樣每個 commit 就只有一行,如果我們想快速的瀏覽很多 commit 的時候就很方便,

像是我們只有自己 commit 所以可以略掉那些作者資訊,最主要有版本號、commit內容跟位在何處就足夠了。

這邊的版本號也縮短了,對 git 來說只要前面的 6 到 8 碼其實就夠了。

那如果前幾碼有重複的話也沒關係,git 會告訴我們無法辨識,此時就再多打幾碼就好。

還有一個 --graph 的參數:

$ git log --oneline --graph
 * 462682d (HEAD -> master) 沒東西
 * 0fdb52f 加入git並新增welcome.txt檔案

跟剛剛的 --oneline 比起來只有一個不同,就是最前面多了 *` 星號。

其實在圖形介面中可以看到,藍色圈圈與空心圈圈,空心圈圈就是 HEAD 所在版本,沒關係,我們看字也看得出來。

進階版

如捰有很多 log 的狀況,需要使用某些條件來查尋 log 而不是逐條逐條的看,應該怎麼做?

# 查詢提交者是 logo 的紀錄
$ git log --oneline --author='logo'
 462682d (HEAD -> master) 沒東西
 0fdb52f 加入git並新增welcome.txt檔案

那因為目前都是 logo 提交的,所以看起來都一樣。

在引號中使用 | 或符號,就可以查到多個提交者的 commit

因為是在引號中,所以在或符號前面要再加上一個反斜線 \ 來跳脫才有效,

不然 git 會以為 | 這個符號也是作者名字的一部份。

想找 commit 內容有提到 東西 這兩個字的紀錄:

$ git log --oneline --grep='東西'
 462682d (HEAD -> master) 沒東西

想找跟 welcome.txt 這個檔案變動有關的紀錄

$ git log --oneline -- welcome.txt
 0fdb52f 加入git並新增welcome.txt檔案

實際上 commit 沒提到這個檔案也無所謂,因為他找的不是 commit 內容而是實際更動的動作。

多檔案就使用空格隔開檔名即可。

而要不要加 --oneline 只是 log 顯示的方式,並不影響搜尋結果。

也可以用時間段來查找相關紀錄,例如查尋今天早上九點到中午十二點的所有紀錄

$ git log --oneline --since="9am" --until="12am"

目前沒有,所以沒有找到。

$ git log --oneline --since="9am" --until="17fm" --after='2020-02-01'
 462682d (HEAD -> master) 沒東西
 0fdb52f 加入git並新增welcome.txt檔案

上面是查找從 2020 年 2 月 1 號以後每天早上 9 點到下午 5 點的所有紀錄。

$ git log --oneline -S '你'
 0fdb52f 加入git並新增welcome.txt檔案

上面的搜尋條件是提交的檔案內容有 這個字的紀錄,

因為我們在該筆紀錄中,welcome.txt 裡有寫入 你好 這兩個字。

其實還有很多參數用法,可以使用 git log --help 來查尋。

與該檔案相關的紀錄

之前我們介紹過 git log 指令來查看我們提交的 log 紀錄。

但我們如果是想觀察跟某個檔案有關的所有 log 提交紀錄時該怎麼辦?

那就加上該檔案的檔名作為參數,即可列出與該檔案相關的紀錄。

$ git log hello.txt
 commit d321f73c6d05ab8b96c5c7f4abb75099d55b823e
 Author: Logo Kuo <logo@forblind.org.tw>
 Date:   Sun Feb 23 22:30:28 2020 +0800

     將 welcome.txt 更名為 hello.txt 並加入 test.py 檔案

當然還是可以搭配之前提的 --oneline 等參數使用。

該提交的實際行為

可是光看到這些紀錄的提交訊息,有時還是無法確定當時到底對他做了什麼事情,

像有時候程式中加了某個功能,在提交紀錄時可以看到說明,但實際到底加了什麼內容還是不清楚,

可以加上 -p 參數,先來加一筆修改紀錄:

# 在 hello.txt 檔案最後加一行字,該行內容為測試兩個字
$ echo '測試' >> hello.txt
# 列出檔案內容
$ cat hello.txt
 你好
 我很好
 測試
# 存到暫存區並提交
$ git add .
$ git commit -m '在 hello.txt 最後加了一行字'
 [master b7df611] 在 hello.txt 最後加了一行字
  1 file changed, 1 insertion(+)

接著看一下詳細 log

$ git log -p hello.txt
 commit b7df611332a5a7f44b667c24e40da1bcc92c00c5
 Author: Logo Kuo <logo@forblind.org.tw>
 Date:   Fri Feb 28 21:31:22 2020 +0800

     在 hello.txt 最後加了一行字

 diff --git a/hello.txt b/hello.txt
 index 65c6e5c..68032d3 100644
 --- a/hello.txt
 +++ b/hello.txt
 @@ -1,2 +1,3 @@
  你好
  我很好
 +測試

 commit d321f73c6d05ab8b96c5c7f4abb75099d55b823e
 Author: Logo Kuo <logo@forblind.org.tw>
 Date:   Sun Feb 23 22:30:28 2020 +0800

     將 welcome.txt 更名為 hello.txt 並加入 test.py 檔案

diff --git a/hello.txt b/hello.txt
 new file mode 100644
 index 0000000..65c6e5c
 --- /dev/null
 +++ b/hello.txt
 @@ -0,0 +1,2 @@
 +你好
 +我很好

雖然格式與內容看起來有點複雜,但大致還是可以看出:

  • 第一筆紀錄的檔案內容 測試 前面有個加號,就表示是該次新增的內容,減號就是刪除的內容
  • 第二筆紀錄是改名,所以有 new file 的標示,內容那兩行就都算是新增出來的,應該還記得更名就是刪除再新增吧

完整內容

上面的紀錄看起來是該提交所做的事情,但我們如果是想看某個檔案的全部內容狀況呢?

例如你發現 hello.txt 的第三行是有問題的,想知道是誰在什麼時候加了這一行,就可以列出檔案完整資訊來觀察,

指令是 blame 後面加檔名:

$ git blame hello.txt
 ^0fdb52f welcome.txt (Logo Kuo 2020-02-16 13:01:25 +0800 1) 你好
 ^0fdb52f welcome.txt (Logo Kuo 2020-02-16 13:01:25 +0800 2) 我很好
 b7df6113 hello.txt   (Logo Kuo 2020-02-28 21:31:22 +0800 3) 測試

以上的資訊非常清楚,包括 hello.txt 還沒被改名時的紀錄都有,

資訊大致上包括:

  • 提交的版本號
  • 檔名
  • 提交者
  • 時間
  • 檔案內的行號
  • 該行的內容

如果檔案很大,只想看某個區間的紀錄,可以使用 -L 參數並指定行號,注意是大寫字母。

$ git blame -L 2,7 test.py
 d321f73c (Logo Kuo 2020-02-23 22:30:28 +0800 2)         '''這是一個銀行類別,裡
 面有存款金額與存錢、提錢等功能'''
 d321f73c (Logo Kuo 2020-02-23 22:30:28 +0800 3)
 d321f73c (Logo Kuo 2020-02-23 22:30:28 +0800 4) class Riches:
 d321f73c (Logo Kuo 2020-02-23 22:30:28 +0800 5)         ''' 這是一個財富類別
 d321f73c (Logo Kuo 2020-02-23 22:30:28 +0800 6)         裡面有兩個屬性,分別是 m
 oney 現金與 mybank 銀行存款
 d321f73c (Logo Kuo 2020-02-23 22:30:28 +0800 7)         '''

以上顯示的是該檔案 test.py 第 2 到 7 行的紀錄。

有時一個專案很久沒碰了,想要繼續更新或新增功能時,可以利用上面這些指令幫你回憶一下上次做了什麼。

當然系統被改壞了用來抓兇手也是很普遍的用法。

所以在使用 log 時可以針對某些條件來調出紀錄,也可以針對某個檔案讀取紀錄,

對於該 log 做了什麼事也能看到,這樣讓我們可以更靈活的利用 git 管理檔案。

補充

以上這些輸出的資訊會比較多,在超過一頁資訊時 git bash 的提示符號會變成 :

此時表示進入了瀏覽狀態,常用指令如下:

  • 空白鍵:下一頁
  • p 上一頁
  • q 離開瀏覽狀態回到 $

而看到提示符號 (END) 就表示看完囉。

如果覺得這樣瀏覽還是不方便,或者有編輯的需求,那就在原本的指令後面加上 > 檔名 把資訊導入某個檔案再使用瀏覽器開啟該檔案進行瀏覽或編輯。

$ git blame test.py > look.txt

還記得之前使用 echo 來把內容加到檔案中吧,就是利用這個原理。

再次提醒,一個大於會把後面的檔案內容清空,然後再新增資訊進去,而兩個大於是把資訊添加在該檔案後面,

而這兩種方式當沒有指定的檔案時都會自行建立一個並添加內容。

刪檔與更名

不管是刪除檔案或更改檔名,對 git 來說就是一種更改紀錄而已。

刪檔

平常我們在工作目錄下運作,通常是使用檔案管理之類的程式來處理檔案。

例如按 delete 或利用快顯功能表的刪除都可以,甚至是 shift+delete 的強制刪除也行。

但我這邊選擇用指令在 git bash 下刪檔,目的是讓大家可以知道我做了什麼事,不然平常是不需要特別開 git bash 刪檔的。

$ rm welcome.txt

$ git status
 On branch master
 Changes not staged for commit:
   (use "git add/rm <file>..." to update what will be committed)
   (use "git restore <file>..." to discard changes in working directory)
         deleted:    welcome.txt

 no changes added to commit (use "git add" and/or "git commit -a")

從上面的資訊我們至少看出兩點:

  1. welcome.txt 上面有 deleted 標誌,表示他被刪了
  2. Changes not staged for commit 表示現在的 git 狀態是做了變更但還沒 add 到暫存區,當然也就還沒 commit 了

那就把他加到暫存區吧

$ git add .
# 接著觀察一下狀態
$ git status
 On branch master
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
         deleted:    welcome.txt

從上面的資訊我們至少看出兩點:

  1. welcome.txt 上面有 deleted 標誌,表示他被刪了
  2. Changes to be committed 表示目前 git 的狀態是已經加到暫存區但還沒 commit 推進倉庫

如果使用 git rm welcome.txt 就是把刪除跟 add 的兩個動作合成一個指令,

實務上很少用,因為我們比較不會在 git bash 下刪檔。

如果使用 --cached 也就是刪除時加上這個參數,

其實不是刪檔,而是移除這個檔案的 git 追蹤,意思就是 git 以後不會再控管他了。

移除追蹤後得到的狀態長這樣:

$ git rm welcome.txt --cached
$ git status
 On branch master
 Changes to be committed:
 (use "git reset HEAD <file>..." to unstage)
 deleted: welcome.txt
 Untracked files:
 (use "git add <file>..." to include in what will be committed)
 welcome.txt

那個 Untracked files 就表示這個檔案已經停止追蹤了。

以上這個 --cached 參數操作我們假設是在其他地方做的不影響原本的工作目錄。

那我們把剛剛刪好檔案的部分 commit 提交上去吧

$ git commit -m '刪除 welcome.txt'
 [master c708443] 刪除 welcome.txt
  1 file changed, 2 deletions(-)
  delete mode 100644 welcome.txt

# 看一下 log
$ git log -1
 commit c708443e21e8fba120ad1437ebc17a3562315559 (HEAD -> master)
 Author: Logo Kuo <logo@forblind.org.tw>
 Date:   Sun Feb 23 21:51:47 2020 +0800

     刪除 welcome.txt

參數 -1 就是只列出最新的一筆 log 資訊。

在這裡讓我們先回到過去還沒刪除 welcome.txt 的美好時光吧,因為我們還沒練習改名。

回春指令之後再解釋,因為我們先把重點放在刪檔與更名上。

$ git reset --hard HEAD~
 HEAD is now at 462682d 沒東西

$ git log -1
 commit 462682ddf12ddebd3e7b4c6796ffb0907560f08b (HEAD -> master)
 Author: Logo Kuo <logo@forblind.org.tw>
 Date:   Sun Feb 16 13:34:36 2020 +0800

     沒東西

$ ls
 welcome.txt

真神奇,剛剛的刪除 commit 紀錄不見了,檔案也回來了。目前先理解成紀錄消失就表示沒做過該紀錄的所有動作。

更名

跟上面刪檔一樣,可以用檔案總管的快顯功能表或快速鍵 F2 來變更檔名,

那我們還是先用指令來更名讓大家看得到動作:

$ mv welcome.txt hello.txt
# 當然還是要看一下狀態
$ git status
 On branch master
 Changes not staged for commit:
   (use "git add/rm <file>..." to update what will be committed)
   (use "git restore <file>..." to discard changes in working directory)
         deleted:    welcome.txt

 Untracked files:
   (use "git add <file>..." to include in what will be committed)
         hello.txt

 no changes added to commit (use "git add" and/or "git commit -a")

雖然是更名,但對 git 來說其實是兩個動作,也就是刪除 welcome.txt 並新增 hello.txt

而且新的檔案狀態是還沒被追蹤。

$ git add .
# 剛開始使用 git 最好做每個動作都仔細觀察狀態,這樣我們才知道 git 到底做了什麼
$ git status
 On branch master
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
         renamed:    welcome.txt -> hello.txt

git 很聰明吧,知道這只是 renamed 更名動作而已。

當然 git mv welcome.txt hello.txt 也可以合併兩段式指令為一個指令了。

記得要 commit 提交才算是完成整個操作流程喔。

不想改名的話就再改回來再提交囉。


來源文章


最後更新:2020-04-17 09:51:48

From: 211.23.21.202

By: 阿慶