當前位置: 妍妍網 > 碼農

Git 不用背

2024-02-28碼農

全文約 14000 字,預計閱讀需要 30 分鐘

當你學習 Git 時,可能會被其龐大的命令集和各種概念所嚇到。但實際上,Git 並不要求死記硬背每一個命令,更重要的是理解其工作流程和使用場景。這篇文章的目的就是幫助你簡化 Git 的學習過程,讓你發現 Git 其實並不需要刻意去背,只需要真正理解它,就能輕松掌握。現在,就讓我們一起踏上探索 Git 世界的旅程吧!

Git 基本概念

1. Git 歷史

Git 是最流行的分布式版本控制系統(Distributed Version Control System,簡稱 DVCS)。它由 Linus Torvalds 建立,當時非常需要一個快速、高效和大規模分布式的原始碼管理系統,用於管理 Linux 原始碼。

由於 Linus 對幾乎所有現有的原始碼管理系統抱有強烈的反感,因此他決定編寫自己的原始碼管理系列。2005 年 4 月,Git 就誕生了。到了 2005 年 7 月,維護工作就交給了 Junio Hamano,自此他就一直在維護這個計畫。

雖然最初只用於 Linux 內核,但 Git 計畫迅速傳播,並很快被用於管理許多其他 Linux 計畫。現在,幾乎所有的軟體開發,尤其是在開源世界中,都是透過 Git 進行的。

2. 版本控制系統

版本控制是指對軟體開發過程中各種程式程式碼、配置檔及說明文件等檔變更的管理,是軟體配置管理的核心思想之一。版本控制技術是團隊協作開發的橋梁,助力於多人協作同步進行大型計畫開發。軟體版本控制系統的核心任務就是查閱計畫歷史操作記錄、實作協同開發。

常見版本控制主要有兩種: 集中式版本控制 分布式版本控制

(1)集中式版本控制系統

集中式版本控制系統,版本庫是集中存放在中央伺服器的。工作時,每個人都要先從中央伺服器獲取最新的版本。完成之後,再把自己添加/修改的內容送出到中央伺服器。所有檔和歷史數據都儲存在中央伺服器上。SVN 是最流行的集中式版本控制系統之一。

集中式版本控制系統的缺點就是必須聯網才能使用,如果使用區域網路還好,速度會比較快。而如果是使用互聯網,網速慢的話,就可能需要等待很長時間。除此之外,如果中央伺服器出現故障,那麽版本控制將不可用。如果中心資料庫損壞,若數據未備份,數據就會遺失。

(2)分布式版本控制系統

分布式版本控制系統,每台終端都可以保存版本庫,版本庫可以不同,可以對每個版本庫進行修改,修改完成後可以集中進行更新。雖然它沒有中心伺服器,但可以有一個備份伺服器,它的功能有點類似於 SVN 的中央伺服器,但它的作用僅是方便交換修改,而不像 SVN 那樣還要負責原始碼的管理。Git 是最流行的分布式版本控制系統之一。

和集中式版本控制系統相比,分布式版本控制系統的安全性要高很多,因為每個人電腦裏都有完整的版本庫,某一個人的電腦損壞不會影響到協作的其他人。

(3)SVN vs Git

Git 相較於 SVN:

  • 送出速度更快: 因為在 SVN 中需要更頻繁地送出到中央儲存庫,所以網路流量會減慢每個人的速度。而使用 Git,主要在本地儲存庫上工作,只需每隔一段時間才送出到中央儲存庫。

  • 沒有單點故障: 使用 SVN,如果中央儲存庫出現故障,則在修復儲存庫之前,其他開發人員無法送出他們的程式碼。使用 Git,每個開發人員都有自己的儲存庫,因此中央儲存庫是否損壞並不重要。開發人員可以繼續在本地送出程式碼,直到中央儲存庫被修復,然後就可以推播他們的更改;

  • 可以離線使用: 與 SVN 不同,Git 可以離線工作,即使網路失去連線,也可以繼續工作而不會遺失功能。

  • 3. Git 安裝

    在Git官網下載、安裝即可: https://git-scm.com/download

    安裝完成之後,可以使用以下命令來檢視 Git 是否安裝成功:

    git--version

    如果安裝成功,終端會打印安裝的 Git 的版本:

    4. Git 初始化

    要給計畫初始化一個Git倉庫,可以在終端中開啟計畫目錄,執行以下命令即可:

    git init

    初始化之後,就會建立一個名為 .git 的新子資料夾,其中包含 Git 將用於跟蹤計畫更改的多個檔和更多子目錄:

    在使用 Git 進行程式碼管理時,不希望一些檔出現在跟蹤列表中,比如 node_modules 檔。這種情況下,可以在計畫的根目錄中建立一個名為.gitignore的檔,在該檔中列出要忽略的檔和資料夾,來看一個範例:

    # 所有以.md結尾的檔
    *.md
    # lib.a不能被忽略
    !lib.a
    # node_modules和.vscode檔被忽略
    node_modules
    .vscode
    # build目錄下的檔被忽略
    build/
    # doc目錄下的.txt檔被忽略
    doc/*.txt
    # doc目錄下多層目錄的所有以.pdf結尾的檔被忽略
    doc/**/*.pdf

    註意:以 # 符號開頭的行是註釋。

    我們可以在本地複制Git儲存庫上的程式碼,首先要找到Git儲存庫上的HTTPS或SSH的地址,如下:

    然後使用以下命令將遠端倉庫複制到本地:

    git clone https://github.com/facebook/react.git

    5. Git 結構和狀態

    從Git的角度來看,可以在三個區域進行檔更改:工作區,暫存區和儲存庫。

  • 工作區: 本地看到的工作目錄;

  • 暫存區: 一般存放在 .git 目錄下的 index 檔(.git/index)中,所以暫存區有時也叫作索引(index)。暫存區是一個臨時保存修改檔的地方;

  • 版本庫: 工作區有一個隱藏目錄 .git ,這個不算工作區,而是 Git 的版本庫,版本庫中儲存了很多配置資訊、日誌資訊和檔版本資訊等。

  • Git 工作目錄下的檔存在兩種狀態:
  • untracked:未跟蹤,未被納入版本控制,即該檔沒有被Git版本管理;

  • tracked:已跟蹤,被納入版本控制,即該檔已被Git版本管理。

  • 其中 已跟蹤狀態 可以細分為以下三種狀態:

  • Unmodified:未修改狀態

  • Modified:已修改狀態

  • Staged:已暫存狀態

  • 可以透過執行以下命令來檢查當前分支的狀態:

    git status

    顯示結果如下:

    此命令不會更改或更新任何內容。它會打印出哪些檔被修改、暫存或未跟蹤。未跟蹤的檔是尚未添加到 git 索引的檔,而自上次送出以來已更改的檔將被視為已被 git 修改。

    Git 入門

    1. 全域配置

    當安裝Git後首先要做的就是配置所有本地儲存庫中使用的使用者資訊。每次Git送出都會使用該使用者資訊。

    config 命令適用於不同的級別:

  • 本地級別: 所有配置都僅限於計畫目錄。預設情況下, 如果未透過任何配置, 則git config將在本地級別寫入;

  • 全域級別: 此配置特定於作業系統上的使用者,配置值位於使用者的主目錄中;

  • 系統級別: 這些配置放在系統的根路徑下,它跟蹤作業系統上的所有使用者和所有儲存庫。

  • 下面的配置均為寫入系統級別:

    (1)設定使用者名稱

    可以使用以下命令設定使用 Git 時的使用者名稱:

    git config --global user.name "name"

    可以使用以下命令檢視設定的 user.name

    git config user.name

    (2)設定信箱

    可以使用以下命令設定使用 Git 時的信箱:

    git config --global user.email "email"

    可以使用以下命令檢視設定的 email:

    git config user.email

    (3)設定命令顏色

    除了上述兩個基本的設定之外,還可以設定命令的顏色,以使輸出具有更高的可讀性:

    git config --global color.ui auto

    (4)檢視所有配置

    透過上面的命令設定的資訊會保存在原生的 .gitconfig 檔中。可以使用以下命令檢視所有配置資訊:

    git config --list

    如果在全域輸入這個命令,就會顯示全域的配置:

    如果在使用 Git 的計畫中輸入該命令,除了會顯示全域的配置之外,還會顯式本地倉庫的一些配置資訊,如下:

    (5)設定別名

    git config 命令為我們提供了一種建立別名的方法,這種別名通常用於縮短現有的命令或者建立自訂命令。來看一個例子:

    git config --global alias.cm "commit -m"

    這裏為 commit -m 建立一個別名 cm ,這樣在送出暫存區檔時,只需要輸入以下命令即可:

    git cm <message>

    2. 分支操作

    分支是原始碼控制的核心概念,它允許將工作分離到不同的分支中,這樣就可以自由地處理原始碼,而不會影響其他任何人的工作或主分支中的程式碼。下面來看一些常見的分支操作。

    (1)檢視分支

    可以使用以下命令來檢視當然所在的分支以及該計畫所有的分支情況:

    git branch

    該命令可以列出計畫所有的 本地分支 ,顯示綠色的分支就是當前分支:

    可以使用以下命令來列出所有的遠端分支:

    git branch -r
    可以使用以下命令來檢視所有的本地分支和遠端分支:

    git branch -a

    (2)建立分支

    我們在電腦上只能存取本地分支,在將分支推播到遠端倉庫之前,需要先建立一個本地分支。

    可以使用以下命令來建立分支:

    git checkout <branch>

    加上 -b 就可以在建立新的分支之後,直接切換到新建立的分支上:

    git checkout -b<branch>

    如果想將新建的本地分支推播到遠端倉庫,以在遠端倉庫添加這個分支。可以執行以下命令:

    git push -u origin <branch>

    (3)刪除分支

    可以使用以下命令來 刪除本地分支

    git branch -d<branch>

    需要註意,在刪除分支之前,要先切換到其他分支,否則就會報錯:

    切換到其他分支再刪除即可: 有時 Git 會拒絕刪除本地分支,因為要刪的分支可能有未送出的程式碼。這是為了保護程式碼以避免意外遺失數據。可以使用以下命令來 強制刪除本地分支

    git branch -D<branch>

    這樣就刪除成功了:

    當然,我們也可以 刪除遠端倉庫分支 ,執行以下命令即可:

    git push origin --delete<name>

    (4)重新命名分支

    可以使用以下命令來將分支重新命名:

    git branch -m<oldname><newname>

    如果 newname 名字分支已經存在,則需要使用 -M 來強制重新命名:

    git branch -M<oldname><newname>

    (5)合並分支(git merge)

    可以使用以下命令將其他分支的程式碼合並到當前分支:

    git merge <branch>

    如果想將A分支合並到B分支,就要先切換到B分支,然後執行命令: git merge A

    (6)合並分支(git rebase)

    git rebase 用於將一個分支的送出記錄合並到另一個分支上。

    原理: 透過找到兩個分支的最近共同祖先,然後提取當前分支相對於該祖先的歷次送出,保存為臨時檔。接著,將當前分支指向目標分支的最新送出,最後依序套用之前保存的修改。這樣,就可以將一個分支上的修改「移動」到另一個分支上,實作程式碼的整合。

    使用 git rebase 的步驟如下:

    1. 確保在正確的分支上,並且該分支已經與遠端分支同步。可以使用 git checkout 命令切換到目標分支,並使用 git pull 命令拉取最新的程式碼。

    2. 執行 git rebase 命令,並指定要合並的分支。例如,如果你想要將當前分支的送出記錄合並到名為 feature 的分支上,可以執行 git rebase feature 命令。

    3. Git會開始分析兩個分支的送出記錄,並嘗試自動合並它們。如果出現沖突,你需要手動解決沖突,並使用 git add 命令標記已解決的檔。然後,使用 git rebase --continue 命令繼續合並過程。

    4. 如果在合並過程中遇到無法自動解決的沖突,可以使用 git rebase --abort 命令中止合並,並返回到原來的狀態。

    5. 一旦所有送出記錄都成功合並,可以使用 git push 命令將更改推播到遠端倉庫。

    假設有一個名為 feature 的分支,它包含了一些新功能的開發程式碼。同時,還有一個名為 master 的主分支,用於釋出穩定版本的程式碼。現在,想要將 feature 分支上的程式碼合並到 master 分支上。首先,切換到master分支,並拉取最新的程式碼:

    git checkout master
    git pull origin master

    然後,執行 rebase 命令,將 feature 分支的送出記錄合並到master分支上:

    git rebase feature

    Git會開始分析兩個分支的送出記錄,並嘗試自動合並它們。如果出現沖突,需要手動解決沖突,並使用 git add 命令標記已解決的檔。例如,假設在合並過程中出現了一個名為 conflict.txt 的檔沖突,你可以使用文字編輯器開啟該檔,解決沖突,然後執行以下命令:

    gitadd conflict.txt
    git rebase --continue

    一旦所有沖突都解決並且所有送出記錄都成功合並,可以使用 git push 命令將更改推播到遠端倉庫:

    git push origin master

    這樣就成功地將 feature 分支上的程式碼合並到了 master 分支上,並保持了送出歷史的清晰和整潔。

    git rebase git merge 都是用於將不同分支的程式碼整合到一起的Git命令,但它們在實作方式、結果和適用場景上有一些區別。

  • 實作方式 git merge 是透過找到兩個分支的最佳同源合並點,將兩個分支中的所有送出都合並到一起,並建立一個新的合並送出。而 git rebase 則是透過找到兩個分支的最近共同祖先,提取當前分支相對於該祖先的歷次送出,然後將當前分支指向目標分支的最新送出,最後依序套用之前保存的修改。

  • 結果 :從最終效果來看, git merge git rebase 都是將不同分支的程式碼融合在一起。但是,它們生成的程式碼樹稍有不同。 git merge 會生成一個新的合並點,保留了歷史記錄中的多個分支合並點,使得歷史記錄更加復雜。而 git rebase 則會將送出歷史「拉直」,使得送出歷史看起來像是一條直線,沒有分叉,歷史記錄更加簡潔。

  • 適用場景 git merge 適用於保留完整的送出歷史,因為它保留了每個分支的合並點,有助於追蹤歷史記錄。它是更為保守的合並方法,相對簡單。而 git rebase 適用於追求整潔的送出歷史,因為它透過重寫歷史記錄來避免不必要的合並送出和分叉。然而,使用 rebase 時需要更多的註意力和精細的操作,因為它可能導致原有的送出變得不可用。

  • 3. 基礎操作

    Git 數據工作流程如下:

    (1)暫存檔

    可以使用以下命令來暫存已修改的檔,命令最後需要指定要暫存的檔名稱:

    gitadd<filename>

    如果想要將所有未跟蹤和修改的檔添加到暫存區,可以執行以下命令:

    gitadd.

    此分時支的狀態如下:

    (2)送出暫存

    可以使用以下命令將暫存區的檔修改送出到本地倉庫,

    git commit -m"meaasge"

    其中 -m 參數列示 message 日誌資訊,參數後面要加一個日誌資訊,用雙引號括起來。

    此分時支的狀態如下:

    如果上次送出暫存的 messge 寫錯了怎麽辦呢?可以使用使用以下命令來更新送出,而不需要撤銷並重新送出:

    git commit --amend-m<message>

    如果有一個新的檔修改,也想送出到上一個commit中,可以使用以下命令來保持相同的送出資訊:

    gitadd.
    git commit --amend --no-edit

    (3)儲存更改

    假如我們正在開發叠代功能,但是還沒開發完。這時有一個緊急的bug需要修復上線。可能就需要切換到一個hotfix分支去修復bug。這時對於開發了一部份的功能建立送出是沒有邏輯意義的。可以使用以下任一命令來儲存修改的內容:

    git stash
    git stash push
    git stash push -m"<stash message>"

    該命令回保存所有未送出的更改並恢復到上次送出時儲存庫的狀態。

    當想再次繼續開發此功能時,就可以使用以下命令檢查所有儲存:

    git stash list

    這時終端中就會顯示帶有時間戳的所有已經暫存的列表。可以使用以下任一命令來取回所有的更改:

    git stash apply
    git stash pop

    apply 和 pop 之間的區別在於,pop 套用了 stash 中的更改並將其也從 stash 中刪除,但 apply 即使在套用後仍將更改保留在 stash 中。

    可以使用以下任一命令套用儲存列表中的第 N 個儲存:

    git stash apply stash@{N}
    git stash apply <n>

    整個過程的輸出如下:

    (4)合並指定送出

    在不同分支之間進行程式碼合並時,通常會有兩種情況:一種情況是需要另一個分支的所有程式碼變動,那麽就可以直接合並(git merge),另一種情況是只需要部份程式碼的變動(某幾次送出),這時就可以使用以下命令來合並指定的送出:

    git cherry-pick <commit hash>

    建議添加 -x 標誌,因為它會生成標準化的送出訊息,通知使用者它是從哪裏pick出來的:

    git cherry-pick -x<commit hash>

    那麽這個 commit hash 是從哪裏來的呢?可以在需要被合並的分支上執行以下命令:

    git log

    這時終端就會顯示出所有的送出資訊:

    這裏黃色文字中 commit 後面的部份就是 commit hash ,復制即可。

    (5)檢查送出

    Git允許我們在本地檢查特定的送出。輸入以下命令就可以檢視有關當前送出的詳細資訊:

    git show

    輸出的結構如下,可以看到,它顯示出了上次送出的commit id、作者資訊(信箱和姓名)、送出日期、commit message、程式碼diff等:

    還可以使用 HEAD~n 語法或送出哈希來檢查過去的送出。使用以下命令就可以獲取往前數的第三次送出的詳細資訊:

    git show HEAD~3

    除此之外,還可以添加一個 --oneline 標誌,以簡化輸出資訊:

    git show --oneline

    這樣送出資訊就簡潔了很多:

    (6)檢視貢獻者

    可以使用以下命令來返回每個貢獻者的commit次數以及每次commit的commit message:

    $ git shortlog

    其可以添加兩個參數:

  • s:省略每次 commit 的註釋,僅僅返回一個簡單的統計。

  • n:按照 commit 數量從多到少的順利對使用者進行排序。

  • 加上這兩個參數之後就可以看到每個使用者中的送出次數以及排名情況:

    git shortlog -sn

    這樣就會顯示出該計畫所有貢獻者的commit次數,從上到下依次減小:

    除此之外,還可以添加一個 --no-merges 標誌,以忽略合並送出的次數:

    git shortlog -sn --no-merges

    (7)倉庫送出歷史

    git rev-list 用於列出倉庫中的送出(commit)記錄。它按照時間倒序顯示送出記錄,並可以根據不同的選項和參數進行篩選和排序。

    下面是 git rev-list 的一些基本用法:

    1. 列出所有送出記錄:

    git rev-list

    這將顯示倉庫中所有的送出記錄,按照時間倒序排列。每個送出記錄都有一個唯一的SHA-1哈希值作為標識。

    1. 列出某個分支的送出記錄:

    git rev-list <branch-name>

    <branch-name> 替換為你要檢視的分支的名稱。這將顯示該分支上的所有送出記錄。

    1. 列出某個送出之後的送出記錄:

    git rev-list <commit-id>..

    <commit-id> 替換為你要檢視的送出的 SHA-1 哈希值。這將顯示該送出之後的所有送出記錄。

    1. 列出兩個送出之間的送出記錄:

    git rev-list <commit-id1>..<commit-id2>

    <commit-id1> <commit-id2> 替換為你要檢視的兩個送出的SHA-1哈希值。這將顯示從 <commit-id1> <commit-id2> 之間的所有送出記錄。

    1. 列出某個檔的所有送出記錄:

    bash復制程式碼
    git rev-list -- <file-path>

    <file-path> 替換為你要檢視的檔的路徑。這將顯示涉及該檔的所有送出記錄。

    (8)添加註釋或備註

    git notes 允許使用者為Git物件(如送出、樹、標簽等)添加註釋或備註資訊。這些註釋資訊是以鍵值對的形式儲存的,其中鍵是一個唯一的參照,而值則是與該參照關聯的註釋內容。

    要使用 git notes ,可以按照以下步驟進行操作:

  • 添加註釋 :使用 git notes add -m "Your note message" <object> 命令向一個物件添加註釋。例如,要向送出 abc123 添加註釋,可以執行 git notes add -m "This is a note for commit abc123" abc123

  • 顯示註釋 :使用 git notes show <object> 命令顯示一個物件的註釋內容。例如,要顯示送出 abc123 的註釋,可以執行 git notes show abc123

  • 編輯註釋 :如果要編輯已存在的註釋,可以使用 git notes edit <object> 命令。這將開啟文字編輯器,允許編輯已存在的註釋內容。編輯完成後,保存並關閉編輯器即可。

  • 顯示所有註釋 :使用 git notes list 命令可以顯示所有物件的註釋資訊。這將列出所有帶有註釋的Git物件及其對應的註釋內容。

  • (9)追溯檔歷史修改記錄

    git blame 用於追溯檔歷史修改記錄,它可以顯示指定檔中每一行程式碼的最後修改者以及修改時間,幫助開發者了解程式碼的演變過程。

    以按照以下步驟使用 git blame 命令:

    1. 開啟終端或命令列界面,並導航到Git倉庫的根目錄。

    2. 執行 git blame <file> 命令,其中 <file> 是要檢視歷史修改記錄的檔的路徑。

    git blame 命令將列出檔的每一行,並顯示最後一次修改該行的送出資訊,包括送出的哈希值、作者、修改時間和送出註釋等。這樣,你可以輕松地找到程式碼中引入bug的送出,或者辨識特定程式碼段的貢獻者。

    除了基本的用法, git blame 命令還接受一些參數來調整輸出。例如,使用 -L <start>,<end> 參數可以指定檢視的行範圍,只顯示指定行範圍內的程式碼修改資訊。使用-p參數可以顯示每一行的詳細資訊,包括送出的哈希值、作者、時間戳和行號。此外,還可以使用 -C -M 選項來尋找程式碼重新命名和移動的情況,以便更好地追蹤程式碼的變化。

    (10)建立存檔

    git archive 用於建立存檔(archive)檔,通常是一個壓縮檔,包含了Git倉庫中的特定檔或目錄。這個命令允許你將Git倉庫中的檔打包成一個獨立的檔,方便備份、傳輸或釋出。

    要使用 git archive 命令,需要指定存檔檔的格式(如.zip、.tar等),以及要包含的檔或目錄。以下是一些常用的 git archive 命令的用法:

  • 建立 tar 格式的存檔檔,包含當前分支的最新程式碼:

  • git archive --format=tar --prefix=my-project/ HEAD |gzip> my-project.tar.gz

    這個命令將建立一個名為 my-project.tar.gz 的壓縮檔,其中包含了當前分支(HEAD)的最新程式碼。 --prefix 選項用於在存檔檔中添加一個字首目錄 my-project/

  • 建立zip格式的存檔檔,只包含指定的檔或目錄:

  • git archive --format=zip --output=my-files.zip path/to/file1 path/to/file2

    這個命令將建立一個名為 my-files.zip 的壓縮檔,其中只包含了指定的檔或目錄。你可以透過路徑來指定要包含的檔或目錄。

    註意, git archive 命令只會包含檔的目前版本,而不會包含Git的後設資料(如送出歷史、分支資訊等)。因此,存檔檔主要用於備份或釋出程式碼,而不是作為完整的Git倉庫來使用。

    (11)驗證送出

    git verify-commit 用於驗證送出(commit)的GPG簽名。GPG(GNU Privacy Guard)是一種加密軟體,可以用於為Git送出添加數位簽名,以確保送出的完整性和真實性。

    要使用 git verify-commit 命令,需要先確保已經為Git配置了GPG簽名,並且至少有一個送出是帶有GPG簽名的。然後按照以下步驟進行操作:

    1. 開啟終端或命令列界面,並導航到Git倉庫的根目錄。

    2. 執行 git verify-commit <commit> 命令,其中 <commit> 是要驗證的送出的哈希值或參照(如分支名、標簽名等)。

    git verify-commit 命令將檢查指定送出的GPG簽名,並輸出驗證結果。如果簽名有效且未被篡改,命令將顯示「Good signature」或類似的訊息。如果簽名無效或存在問題,命令將顯示相應的錯誤訊息。

    除了基本的用法, git verify-commit 命令還接受一些參數來調整輸出和行為。例如,使用 --raw 參數可以打印原始的GPG狀態輸出,而不是人類可讀的輸出。使用 --verbose 參數可以打印送出物件的詳細內容,以便更詳細地了解驗證過程。

    註意,要使用 git verify-commit 命令,必須已經為Git配置了GPG簽名,並且至少有一個送出是帶有GPG簽名的。如果送出沒有簽名或簽名無效,該命令將無法驗證送出的真實性。

    4. 遠端操作

    (1)檢視遠端倉庫

    可以使用以下命令來檢視遠端倉庫:

    git remote

    該命令會列出指定的每一個遠端伺服器的簡寫。如果已經複制了遠端倉庫,那麽至少應該能看到 origin ,這是 Git 複制的倉庫伺服器的預設名字:

    可以執行以下命令來獲取遠端倉庫的地址:

    git remote -v

    其中 fetch 是獲取, push 是推播:

    可以使用以下命令來檢視更加詳細的資訊:

    git remote show origin

    輸出結果如下:

    (2) 添加遠端倉庫

    可以使用以下命令來將本地計畫連結到遠端倉庫:

    git remote add<remote_name><remote_url>

    其中:

  • remote_name :倉庫名稱(預設是origin)

  • remote_url :遠端倉庫地址

  • 該命令允許 Git 跟蹤遠端儲存庫並將本地儲存庫連線到遠端倉庫。

    (3) 移除遠端倉庫

    可以使用命令來移除遠端倉庫:

    git remote rm origin

    需要註意,該命令只是從本地移除遠端倉庫的記錄(也就是解除本地倉庫和遠端倉庫的關系),並不會真正影響到遠端倉庫。

    (4) 從遠端倉庫抓取與拉取

    可以使用以下命令來從遠端倉庫獲取最新版本到本地倉庫,不會自動merge(合並數據):

    git fetch

    由於該命令不會自定合並數據,所以該命令執行完後需要手動執行 git merge 遠端分支到所在的分支。

    可以使用以下命令來將 遠端指定分支 拉取到 本地指定分支上

    git pull origin <遠端分支名>:<本地分支名>

    使用以下命令來將 遠端指定分支 拉取到 本地當前分支上

    git pull origin <遠端分支名>

    使用以下命令開將 與本地當前分支同名的遠端分支 拉取到 本地當前分支上:

    git pull

    註意:如果當前本地倉庫不是從遠端倉庫複制,而是本地建立的倉庫,並且倉庫中存在檔,此時再從遠端倉庫拉取檔的時候會報錯( fatal: refusing to merge unrelated histories ),解決此問題可以在 git pull 命令後加入參數 --allow-unrelated-histories ,即:

    git pull --allow-unrelated-histories

    (5)推播到遠端倉庫

    可以使用以下命令將 本地指定分支 推播到 遠端指定分支上

    git push origin <本地分支名>:<遠端分支名>

    可以使用以下命令將 本地指定分支 推播到 與本地當前分支同名的遠端分支上:

    git push origin <本地分支名>

    使用以下命令將 本地當前分支 推播到 與本地當前分支同名的遠端分支上

    git push

    可以使用以下命令來將本地分支與遠端同名分支相關聯:

    git push -u origin <本地分支名>

    由於遠端庫是空的,第一次推播master分支時,加上了-u參數,Git不但會把原生的master分支內容推播的遠端新的master分支,還會把原生的master分支和遠端的master分支關聯起來,在以後的推播或者拉取時就可以簡化命令為git push。

    Git 進階

    1. 修改操作

    如果只是簡單地從工作目錄中手工刪除檔,執行 git status 時就會在 Changes not staged for commit 的提示

    (1)刪除檔

    可以使用以下命令將檔從暫存區和工作區中刪除:

    gitrm<filename>

    如果刪除之前修改過並且已經放到暫存區域的話,則必須要用強制刪除選項 -f

    gitrm-f<filename>

    如果想把檔從暫存區域移除,但仍然希望保留在當前工作目錄中,換句話說,僅是從跟蹤清單中刪除,使用 --cached 選項即可:

    gitrm--cached<filename>

    可以使用以下命令進行遞迴刪除,即如果後面跟的是一個目錄做為參數,則會遞迴刪除整個目錄中的所有子目錄和檔:

    gitrm –r *

    進入某個目錄中,執行此語句,就會刪除該目錄下的所有檔和子目錄。

    (2)取消修改

    取消修改有三種情況:

    1)未使用 git add 將修改檔添加到暫存區 這種情況下,可以使用以下命令來撤銷所有還沒有加入到緩存區的修改:

    git checkout -- <filename>

    需要註意,此檔不會刪除新建的檔,因為新建的檔還沒加入到Git管理系統重,所以對Git來說事未知的,需要手動刪除。

    2)已使用 git add 將修改檔添加到暫存區,未使用 git commit 送出緩存 這種情況下,相當於撤銷了 git add 命令對於檔修改的緩存:

    git reset HEAD <filename>

    上面的命令可以撤銷指定檔的緩存,要想放棄所有檔的緩存,可以執行以下命令:

    git reset HEAD

    需要註意,在使用此命令後,原生的修改並不會消失,而會回到第一種情況。要想撤銷原生的修改,執行第一種情況中的命令即可。

    除此之外,還可以指定返回到N次送出之前的階段,執行以下命令即可:

    git reset HEAD~N

    這樣就能退回到n個版本之前,同樣不會修改本地檔的內容,這些新的內容會變成未更新到緩存區的狀態。

    3)已使用 git commit 送出緩存 這種情況下,可以使用以下命令來回退到上一次 commit 的狀態:

    git reset --hard HEAD^

    也可以使用以下命令來回退到任意版本:

    git reset --hard<commit_id>

    註意,使用 git log 命令來檢視 git 送出歷史和 commit id。

    (3)恢復刪除內容

    這是一個很重要的命令,假如回退到某個舊版本,現在想恢復到新版本,又找不到新版本的 commit id 怎麽辦?Git 提供了下面的命令用來記錄每一次命令:

    git reflog show HEAD
    git reflog

    執行之後輸出如下:

    可以看到,最左側黃色字型就是修改的 commit id,根據這個id就可以將程式碼恢復到對應節點位置。HEAD@{n}表示HEAD更改歷史記錄,最近的操作在上面。

    假如需要把程式碼回退到 HEAD@{5} 處,可以執行以下命令:

    git reset --hard HEAD@{5}

    或者執行下面的命令:

    git reset --hard 8a0fd74

    需要註意,如果有任何本地修改,該命令也會將其銷毀,因此在 reset 之前建議使用 stash 將本地修改儲存。

    (4)刪除未跟蹤檔

    git clean 用於從工作目錄中刪除未跟蹤的檔。這些檔通常是那些由編輯器、構建過程或其他工具生成的臨時檔或副產品,而不是Git倉庫中的一部份。使用git clean命令可以幫助保持工作目錄的整潔,避免這些未跟蹤的檔幹擾正常的Git操作或導致意外的送出。

    git clean 命令的基本語法如下:

    git clean [-dfnxq][-e <pattern>][-i][-n][-f][-r | -R][<path>...]

    下面是一些常用的選項和參數:

  • -d :刪除未跟蹤的目錄和檔。預設情況下, git clean 只刪除未跟蹤的檔。

  • -f :強制執行刪除操作,不會提示使用者確認。

  • -n :僅顯示將要刪除的檔和目錄列表,而不實際刪除它們。這可以用於檢查將要刪除的內容。

  • -x :刪除所有未跟蹤的檔和目錄,包括被 .gitignore 檔忽略的檔和目錄。

  • -q :靜默模式,不輸出任何資訊。

  • -e <pattern> :指定要排除的檔模式。可以使用通配符來匹配要排除的檔或目錄。

  • -i :互動式模式,會提示使用者確認每個要刪除的檔或目錄。

  • <path>... :指定要清理的路徑。如果不指定路徑,將預設清理整個工作目錄。

  • 以下是一些使用 git clean 命令的範例:

    1. 刪除所有未跟蹤的檔和目錄:

    git clean -df

    1. 僅顯示將要刪除的檔和目錄列表:

    git clean -n

    1. 強制執行刪除操作,不提示使用者確認:

    git clean -f

    1. 刪除所有未跟蹤的檔和目錄,包括被 .gitignore 檔忽略的內容:

    git clean -dfx

    註意,使用git clean命令時要小心,確保不會誤刪除重要的檔。在執行刪除操作之前,最好先使用 -n 選項來預覽要刪除的內容。

    git rm git clean 都是刪除檔,那他們之間有什麽區別呢?

  • git rm 主要用於從暫存區及版本庫中刪除已跟蹤的檔。換句話說,這個命令針對的是已經被Git管理的檔。如果你嘗試使用 git rm 刪除一個未被Git跟蹤的檔,它將不會有任何效果。

  • git clean 命令則主要用於刪除工作區中的未跟蹤檔,即那些未被Git管理的檔。這些檔可能是由編輯器、構建過程或其他工具生成的臨時檔或副產品。 git clean 操作其實更像純粹的 rm 命令,但能夠方便地刪除未跟蹤檔。

  • 2. 標簽操作

    標簽指的是 某個分支某個特定時間點的狀態 ,透過標簽可以很方便的了解到標記時的狀態。

    標簽有兩種型別 :

  • 輕量標簽 : 只是某個commit 的參照,可以理解為是一個commit的別名;

  • 附註標簽 : 儲存在Git倉庫中的一個完整物件,包含打標簽者的名字、電子信件地址、日期時間 以及其他的標簽資訊。它是可以被校驗的,可以使用 GNU Privacy Guard (GPG) 簽名並驗證。

  • (1)展示標簽

    可以使用以下命令來獲取所有標簽:

    git tag

    它會列出所有標簽的名稱:

    可以使用以下命令來檢視某一個標簽的詳細資訊:

    git show <tag_name>
    還可以根據條件來顯示標簽,比如列出以 v1. 開頭的所有tag:

    git tag -l"v1."

    (2)建立標簽

    可以使用以下命令在本地建立新標簽:

    git tag <tag_name>

    例如:

    git tag v1.0.0

    通常遵循的命名模式如下:

    v<major>.<minor>.<patch>

  • major(主版本號):重大變化

  • minor(次要版本號):版本與先前版本相容

  • patch(修補程式號):bug修復

  • 除此之外,我們還可以為特定的commit建立標簽,其命令格式如下:

    git tag <tagname><commit_sha>

    以上面的的形式建立的標簽都屬於輕量標簽,下面來看看如何建立一個附註標簽。

    在建立標簽時,可以添加一個 -a 標誌以建立一個帶備註的標簽,備註資訊使用 -m message 來指定:

    git tag -a<tagname>-m"<message>"

    (3)推播標簽

    標簽建立完成之後就可以使用以下命令將其推播到遠端倉庫:

    git push origin --tags

    以上命令會將本地所有tag都推播到遠端倉庫。如果想推播指定標簽,可以執行以下命令:

    git push origin <tagname>

    (4)切換標簽

    可以使用以下命令來切換標簽:

    git checkout <tagname>

    (5)刪除標簽

    可以使用以下命令來刪除本地倉庫指定標簽:

    git tag -d<tagname>

    可以使用以下命令來刪除遠端倉庫指定標簽:

    git push origin :refs/tags/<tagname>

    也可以使用以下命令來刪除遠端倉庫的指定標簽:

    git push origin --delete<tagname>

    (6)拉取標簽

    可以使用以下命令來將遠端倉庫的標簽拉取(同步)到當前分支:

    git fetch --tags

    (7)檢出標簽

    檢出標簽實際上就是在標簽的基礎上進行其他開發或操作。需要以標簽指定的版本為基礎版本,新建一個分支,繼續其他的操作。執行以下命令即可:

    git checkout -b<branch><tagname>

    (8)驗證標簽

    git verify-tag 用於驗證標簽(tag)的 GPG 簽名。GPG(GNU Privacy Guard)是一種用於檔簽名的工具,它可以確保標簽的完整性和真實性,防止標簽被篡改或偽造。

    要使用 git verify-tag 命令,需要先確保已經為 Git 配置了 GPG 簽名。然後,可以按照以下步驟進行操作:

    1. 開啟終端或命令列界面,並導航到 Git 倉庫的根目錄。

    2. 執行 git verify-tag <tag> 命令,其中 <tag> 是要驗證的標簽名稱。

    git verify-tag 命令將檢查指定標簽的 GPG 簽名,並輸出驗證結果。如果簽名有效且未被篡改,命令將顯示 "Good signature" 或類似的訊息。如果簽名無效或存在問題,命令將顯示相應的錯誤訊息。

    除了基本的用法, git verify-tag 命令還接受一些參數來調整輸出和行為。例如,使用 --raw 參數可以打印原始的 GPG 狀態輸出,而不是人類可讀的輸出。使用 --verbose 參數可以打印標簽物件的詳細內容,以便更詳細地了解驗證過程。

    3. 日誌記錄

    (1)基礎日誌

    可以使用以下命令來檢視分支的歷史送出資訊:

    git log

    這是其最基礎的用法,輸出如下:

    可以看到,終端上輸出了該分支近期的送出記錄,它包含了所有貢獻者的送出。

    (2)按作者檢視

    如果想只看某個人的送出,可以添加過濾條件:

    git log --author="username"

    當然也可以搜尋多個作者的送出資訊,只需要在用|分隔使用者名稱即可,註意需要使用\來對|進行轉義:

    git log --author="username1\|usernmae2"

    這裏列出的是每次送出的詳細資訊,如果指向看到每個送出的概要,可以在命令中添加 --oneline 標誌:

    git log --author="username"--oneline

    (3)按時間檢視

    除了可以按照作者來檢視日誌之外,還可以按照時間檢視日誌。可以檢視某個時間之前的日誌,也可以檢視某個日期之後的日誌:

    //某個日期之後
    git log --since=<date>
    git log --after=<date>
    //某個日期之前
    git log --until=<date>
    git log --before=<date>

    如果想檢視某個具體時間區間之間的日誌,可以組合以上參數:

    git log --since="2022.05.15"--until="2022.05.20"

    (4)按檔檢視

    如果我們想檢視某個檔都在哪些送出中修改了內容,也是可以的。使用以下命令即可:

    git log -- <path>

    比如檢視 README.md 檔的修改記錄:

    (5)按合並檢視

    在歷史送出中可能會有很多次合並的送出記錄,想要只檢視程式碼合並的記錄,可以執行以下命令:

    git log --merges

    如果想檢視非合並操作的操作記錄,可以執行以下命令:

    git log --no-merges

    (6)按分支檢視

    可以按照分支檢視日誌,如果想檢視 test 分支比 master 分支多送出了哪些內容,就可以執行以下命令:

    git log master..test

    相反,如果想看 master 分支比 test 分支多送出了哪些內容,就可以執行以下命令:

    git log test..master

    (7)美化日誌

    git log命令可以用來檢視送出歷史,此命令的問題在於,隨著計畫復雜性的增加,輸出變得越來越難閱讀。可以使用以下命令來美化日誌的輸出:

    git log --graph--oneline--decorate

    輸出結果如下,這樣就能看到更簡潔的細分以及不同分支如何連線在一起:

    (8)其他標誌

    上面我們提到了,可以使用 --oneline 標誌來簡化日誌的輸出:

    git log --oneline

    可以使用 --stat 標誌來簡要顯示檔增改行數統計,每個送出都列出了修改過的檔,以及其中添加和移除的行數,並在最後列出所有增減行數小計:

    git log --stat

    可以添加 -N 標誌來僅顯示最近N次的送出,其中 N 是一個正整數,例如檢視最近三次送出:

    git log -3

    可以使用 -p 標誌來展開顯示每次送出的內容差異對比:

    git log -p

    註意,以上這些命令識別元都可以組合使用。

    4. 差異對比

    git diff 命令可以用來比較檔的不同,即比較檔在 暫存區 工作區 的差異。

    (1)未緩存改動

    當工作區有改動,暫存區為空時, diff對比的是工作區與最後一次commit送出的共同檔;當工作區有改動,暫存區不為空時,diff對比的是工作區與暫存區的共同檔。

    (2)已緩存改動

    當已緩存改動時,可以使用以下任一命令來顯示暫存區(已add但未commit檔)和最後一次commit(HEAD)之間的所有不相同檔的差異對比:

    gitdiff--cached
    gitdiff--staged

    (3)已緩存和未緩存改動

    可以使用以下命令來顯示工作目錄(已修改但未add檔)和暫存區(已add但未commit檔)與最後一次commit之間的的所有不相同檔的差異對比:

    gitdiff HEAD

    (4)不同分支差異

    可以使用以下命令來比較兩個分支上最後 commit 的內容的差別:

    gitdiff<分支名1><分支名2>

    這樣就可以顯示出兩個分支的詳細差異,如果只是想看有哪些檔存在差異,可以在命令中添加 --stat 標誌,這樣就不會顯示每個檔的內容的詳細對比:

    gitdiff<分支名1><分支名2>--stat

    5. 定位問題

    git bisect 采用二分尋找演算法來幫助開發者快速定位引入問題的送出。當在程式碼庫中遇到錯誤,但不確定何時引入時,git bisect可以顯著提高尋找錯誤的效率。

    原理: git bisect 使用二分尋找演算法來縮小引入問題的送出範圍。它首先將送出歷史分為兩半,然後詢問開發者哪一半包含引入錯誤的送出。基於開發者的反饋,git bisect會繼續將範圍縮小到更小的一半,直到找到引入問題的確切送出。

    使用 git bisect 的基本步驟如下:

    1. 確定一個包含錯誤的送出(bad commit)和一個不包含錯誤的送出(good commit)。這通常透過手動檢查送出歷史或使用其他工具來完成。

    2. 從頂層工作目錄開始,執行 git bisect start 來啟動二分尋找過程。

    3. 使用 git bisect bad <bad-commit> 將包含錯誤的送出標記為bad。

    4. 使用 git bisect good <good-commit> 將不包含錯誤的送出標記為good。

    5. Git現在會計算出中間送出,並簽出該送出。你需要透過測試來確定該送出是否包含錯誤。

    6. 如果中間送出包含錯誤,執行 git bisect bad 。如果不包含錯誤,執行 git bisect good

    7. Git將基於你的反饋繼續縮小範圍,並簽出下一個中間送出。重復步驟5和6,直到找到引入問題的確切送出。

    8. 一旦找到引入問題的送出, git bisect 將打印出相應的送出哈希。你可以使用 git bisect reset 來重設工作樹,完成整個尋找過程。

    假設 發現了一個錯誤。 不確定這個錯誤是在何時引入的,但是知道在某個特定版本的程式碼中該錯誤是不存在的。

    1. 首先,確定一個包含錯誤的送出(bad commit)和一個不包含錯誤的送出(good commit)。假設你知道在送出 abc123 時程式碼是工作的,而在送出 def456 時程式碼已經出現了錯誤。

    2. 從計畫的頂層工作目錄開始,執行 git bisect start

    3. 使用 git bisect bad def456 將送出 def456 標記為bad。

    4. 使用 git bisect good abc123 將送出 abc123 標記為good。

    5. Git將計算出這兩個送出之間的中間送出,並簽出該送出。你需要測試這個送出來確定是否包含錯誤。

    6. 假設測試結果顯示中間送出包含錯誤,執行 git bisect bad 。Git將繼續在bad和中間送出之間尋找。

    7. 重復步驟5和6,直到Git找到引入問題的確切送出。

    8. 一旦找到引入問題的送出,可以使用 git bisect reset 來重設工作樹,並繼續你的開發工作。

    Git 實用工具

    1. GitLens

    GitLens 是一個VS Code外掛程式,可以用來檢視計畫的送出記錄、檔修改記錄、顯示每行程式碼的送出記錄等。透過豐富的視覺化和強大的比較命令 獲得有價值的見解

    2. Git History

    Git History 是一個VS Code外掛程式,增強了Git 的功能,它可以用來檢視日誌資訊,檢視和搜尋歷史,進行分支對比、送出對比,跨送出對比檔等。

    3. Git Automator

    Git Automator 是一個VS Code外掛程式,主要用來自動化Git送出訊息和 Git 工作流程。它允許用一個捷徑添加和送出檔。它還為送出資訊提供了自動填充功能。當動作很明顯時,例如你刪除了一個檔,Git Automator 會猜測該動作並將其添加到預填充的送出訊息中。

    4. LearnGitBranching

    LearnGitBranching 是一個 git 儲存庫視覺化工具、沙箱和一系列教程和挑戰。它的主要目的是幫助開發人員透過視覺化的力量來理解 git。這是透過不同級別的遊戲來熟悉不同的git命令來實作的。

    Github: https://github.com/pcottle/learnGitBranching

    往期推薦