Git
English ▾ 主題 ▾ 最新版本 ▾ gitattributes 最後更新於 2.46.0

名稱

gitattributes - 定義每個路徑的屬性

概要

$GIT_DIR/info/attributes, .gitattributes

說明

gitattributes 檔案是一個簡單的文字檔,可為路徑名稱指定 attributes (屬性)。

gitattributes 檔案中的每一行都採用以下格式

pattern attr1 attr2 ...

也就是說,一個模式後接一個屬性列表,以空白分隔。開頭和結尾的空白會被忽略。以 # 開頭的行會被忽略。以雙引號開頭的模式會以 C 風格引用。當模式符合所討論的路徑時,該行上列出的屬性會賦予該路徑。

對於給定的路徑,每個屬性都可能處於下列其中一種狀態

設定

該路徑具有屬性,且特殊值為「true」;這透過僅在屬性列表中列出屬性名稱來指定。

取消設定

該路徑具有屬性,且特殊值為「false」;這透過在屬性列表中列出以破折號 - 作為前綴的屬性名稱來指定。

設定為值

該路徑具有屬性,且指定字串值;這透過在屬性列表中列出屬性名稱,後接等號 = 及其值來指定。

未指定

沒有模式符合該路徑,且沒有任何項目指出該路徑是否具有該屬性,因此該路徑的屬性被視為「未指定」。

當有多個模式符合該路徑時,後面的行會覆寫前面的行。這種覆寫是針對每個屬性完成的。

模式符合路徑的規則與 .gitignore 檔案中的規則相同 (請參閱 gitignore[5]),但有幾個例外

  • 禁止負模式

  • 符合目錄的模式不會以遞迴方式符合該目錄內的模式 (因此在屬性檔案中使用尾隨斜線 path/ 語法是沒有意義的;請改用 path/**)

在決定哪些屬性被賦予到路徑時,Git 會諮詢 $GIT_DIR/info/attributes 檔案 (具有最高的優先順序)、與所討論路徑相同目錄中的 .gitattributes 檔案,以及其父目錄直到工作樹的頂層 (包含 .gitattributes 的目錄距離所討論路徑越遠,其優先順序越低)。最後,會考量全域和系統範圍的檔案 (它們具有最低的優先順序)。

當工作樹中缺少 .gitattributes 檔案時,索引中的路徑會用作回退機制。在結帳過程中,會使用索引中的 .gitattributes,然後再使用工作樹中的檔案作為回退機制。

如果您希望只影響單一儲存庫 (亦即,為特定於該儲存庫的某個使用者工作流程的檔案指派屬性),則應該將屬性放置在 $GIT_DIR/info/attributes 檔案中。應進行版本控制並分發到其他儲存庫的屬性 (亦即,所有使用者都感興趣的屬性) 應放入 .gitattributes 檔案中。應影響單一使用者所有儲存庫的屬性應放置在 core.attributesFile 配置選項指定的檔案中 (請參閱 git-config[1])。其預設值為 $XDG_CONFIG_HOME/git/attributes。如果未設定 $XDG_CONFIG_HOME 或為空,則會改為使用 $HOME/.config/git/attributes。系統上所有使用者的屬性應放置在 $(prefix)/etc/gitattributes 檔案中。

有時,您可能需要將路徑的屬性設定覆寫為 Unspecified 狀態。這可以透過列出以驚嘆號 ! 作為前綴的屬性名稱來完成。

保留的內建屬性

builtin_* 是內建屬性值的保留命名空間。此命名空間下任何使用者定義的屬性都會被忽略,並觸發警告。

builtin_objectmode

此屬性用於依其檔案位元模式 (40000、120000、160000、100755、100644) 篩選檔案。例如::(attr:builtin_objectmode=160000)。您也可以使用 git check-attr builtin_objectmode -- <file> 檢查這些值。如果物件不在索引中,git check-attr --cached 將會傳回「未指定」。

效果

透過為路徑指派特定屬性,可以影響 Git 的某些操作。目前,下列操作可感知屬性。

結帳和簽入

這些屬性會影響在執行 git switchgit checkoutgit merge 等命令時,如何將儲存在儲存庫中的內容複製到工作樹檔案。它們也會影響 Git 在 git addgit commit 時,如何將您在工作樹中準備的內容儲存在儲存庫中。

text

此屬性會將路徑標記為文字檔,這會啟用行尾轉換:當相符的檔案新增至索引時,檔案的行尾會在索引中正規化為 LF。相反地,當檔案從索引複製到工作目錄時,其行尾可能會根據 eol 屬性、Git 配置和平台,從 LF 轉換為 CRLF (請參閱下面 eol 的說明)。

設定

在路徑上設定 text 屬性會如上所述啟用簽入和結帳時的行尾轉換。每次簽入檔案時,行尾都會在索引中正規化為 LF,即使檔案先前已以 CRLF 行尾新增至 Git 也是如此。

取消設定

在路徑上取消設定 text 屬性會告訴 Git 在簽入或結帳時不要嘗試任何行尾轉換。

設定為字串值「auto」

text 設定為「auto」時,Git 會自行決定檔案是文字檔還是二進位檔。如果它是文字檔,且檔案先前未使用 CRLF 結尾在 Git 中,則會在簽入和結帳時轉換行尾,如上所述。否則,在簽入或結帳時不會進行轉換。

未指定

如果未指定 text 屬性,則 Git 會使用 core.autocrlf 配置變數來決定是否應該轉換檔案。

任何其他值都會導致 Git 的行為如同 text 保持未指定。

eol

此屬性會標記路徑,以在結帳時使用工作樹中特定的行尾樣式。只有在設定 texttext=auto 時才會生效 (請參閱上方),但如果 text 保持未指定,則指定 eol 會自動設定 text

設定為字串值「crlf」

此設定會在結帳時,將工作目錄中檔案的行尾轉換為 CRLF。

設定為字串值「lf」

此設定會在結帳時,於工作目錄中使用與索引中相同的行尾。

未指定

如果未為檔案指定 eol 屬性,則工作目錄中檔案的行尾會由 core.autocrlfcore.eol 配置變數決定 (請參閱 git-config[1] 中這些選項的定義)。如果已設定 text,但未設定這些變數,則預設值為 Windows 上的 eol=crlf 和所有其他平台上的 eol=lf

crlf 屬性的回溯相容性

為實現回溯相容性,crlf 屬性的解讀方式如下

crlf		text
-crlf		-text
crlf=input	eol=lf

行尾轉換

雖然 Git 通常會保持檔案內容不變,但可以將其設定為將行尾正規化為儲存庫中的 LF,並選擇性地在結帳檔案時將其轉換為 CRLF。

如果您只是想要讓工作目錄中具有 CRLF 行尾,而與您正在使用的儲存庫無關,您可以設定配置變數「core.autocrlf」,而無需使用任何屬性。

[core]
	autocrlf = true

這不會強制正規化文字檔,但會確保您引入儲存庫的文字檔在新增時,會將其行尾正規化為 LF,且已在儲存庫中正規化的檔案保持正規化。

如果您想要確保任何參與者引入儲存庫的文字檔,其行尾都會正規化,您可以為所有檔案將 text 屬性設定為「auto」。

*	text=auto

這些屬性允許對行尾轉換進行細微的控制。以下範例會讓 Git 規範化 .txt、.vcproj 和 .sh 檔案,確保 .vcproj 檔案在工作目錄中有 CRLF,而 .sh 檔案有 LF,並防止 .jpg 檔案被規範化,無論其內容為何。

*               text=auto
*.txt		text
*.vcproj	text eol=crlf
*.sh		text eol=lf
*.jpg		-text
注意
當在跨平台專案中使用 push 和 pull 到中央儲存庫時,啟用 text=auto 轉換時,應規範化包含 CRLF 的文字檔案。

從乾淨的工作目錄開始

$ echo "* text=auto" >.gitattributes
$ git add --renormalize .
$ git status        # Show files that will be normalized
$ git commit -m "Introduce end-of-line normalization"

如果有任何不應規範化的檔案出現在 git status 中,請在執行 git add -u 之前取消設定其 text 屬性。

manual.pdf	-text

相反地,Git 未偵測到的文字檔案可以手動啟用規範化。

weirdchars.txt	text

如果 core.safecrlf 設定為 "true" 或 "warn",Git 會驗證對於目前的 core.autocrlf 設定,轉換是否可逆。對於 "true",Git 會拒絕不可逆的轉換;對於 "warn",Git 只會印出警告,但會接受不可逆的轉換。安全機制會觸發以防止對工作樹中的檔案進行此類轉換,但有一些例外。即使…

  • git add 本身不會接觸工作樹中的檔案,但下一次的 checkout 會,因此安全機制會觸發;

  • git apply 使用 patch 更新文字檔案會接觸工作樹中的檔案,但該操作是關於文字檔案的,而 CRLF 轉換是關於修正行尾不一致的問題,因此安全機制不會觸發;

  • git diff 本身不會接觸工作樹中的檔案,它通常用於檢查您打算下一步 git add 的變更。為了及早發現潛在的問題,安全機制會觸發。

working-tree-encoding

Git 將以 ASCII 或其超集合之一(例如 UTF-8、ISO-8859-1 等)編碼的檔案識別為文字檔案。以某些其他編碼(例如 UTF-16)編碼的檔案會被解讀為二進位檔案,因此內建的 Git 文字處理工具(例如 git diff)以及大多數 Git 網頁前端預設不會顯示這些檔案的內容。

在這些情況下,您可以使用 working-tree-encoding 屬性告知 Git 工作目錄中檔案的編碼。如果將具有此屬性的檔案新增至 Git,則 Git 會將內容從指定的編碼重新編碼為 UTF-8。最後,Git 會將 UTF-8 編碼的內容儲存在其內部資料結構(稱為「索引」)中。在 checkout 時,內容會重新編碼回指定的編碼。

請注意,使用 working-tree-encoding 屬性可能會有一些陷阱

  • 替代的 Git 實作(例如 JGit 或 libgit2)和舊版的 Git(截至 2018 年 3 月)不支援 working-tree-encoding 屬性。如果您決定在您的儲存庫中使用 working-tree-encoding 屬性,強烈建議您確保所有使用該儲存庫的用戶端都支援它。

    例如,Microsoft Visual Studio 資源檔案 (*.rc) 或 PowerShell 腳本檔案 (*.ps1) 有時會以 UTF-16 編碼。如果您將 *.ps1 宣告為 UTF-16 檔案,並且您使用已啟用 working-tree-encoding 的 Git 用戶端新增 foo.ps1,則 foo.ps1 將以 UTF-8 格式內部儲存。不支援 working-tree-encoding 的用戶端會將 foo.ps1 以 UTF-8 編碼的檔案 checkout。這通常會對此檔案的使用者造成麻煩。

    如果一個不支援 working-tree-encoding 屬性的 Git 用戶端新增了一個新的檔案 bar.ps1,則 bar.ps1 將以「原樣」內部儲存(在此範例中,可能為 UTF-16)。支援 working-tree-encoding 的用戶端會將內部內容解讀為 UTF-8,並嘗試在 checkout 時將其轉換為 UTF-16。該操作會失敗並導致錯誤。

  • 將內容重新編碼為非 UTF 編碼可能會導致錯誤,因為轉換可能不是 UTF-8 來回安全。如果您懷疑您的編碼不是來回安全,請將其新增至 core.checkRoundtripEncoding,讓 Git 檢查來回編碼(請參閱 git-config[1])。SHIFT-JIS(日文字元集)已知與 UTF-8 有來回問題,預設會檢查此問題。

  • 重新編碼內容需要資源,這可能會減慢某些 Git 操作(例如 git checkoutgit add)。

只有在您無法以 UTF-8 編碼儲存檔案,並且希望 Git 能夠將內容視為文字處理時,才使用 working-tree-encoding 屬性。

例如,如果您的 *.ps1 檔案是以帶位元組順序標記 (BOM) 的 UTF-16 編碼,並且您希望 Git 根據您的平台執行自動行尾轉換,請使用以下屬性。

*.ps1		text working-tree-encoding=UTF-16

如果您的 *.ps1 檔案是以不帶 BOM 的 UTF-16 小端編碼,並且您希望 Git 在工作目錄中使用 Windows 行尾(如果您想要帶 BOM 的 UTF-16 小端,請使用 UTF-16LE-BOM 而不是 UTF-16LE)。請注意,如果使用 working-tree-encoding 屬性以避免歧義,強烈建議使用 eol 明確定義行尾。

*.ps1		text working-tree-encoding=UTF-16LE eol=crlf

您可以使用以下命令取得平台上所有可用編碼的清單

iconv --list

如果您不知道檔案的編碼,則可以使用 file 命令猜測編碼

file foo.ps1

ident

當為路徑設定 ident 屬性時,Git 會在 checkout 時將 blob 物件中的 $Id$ 替換為 $Id:,後接 40 個字元的十六進位 blob 物件名稱,然後是一個美元符號 $。工作樹檔案中任何以 $Id: 開頭並以 $ 結尾的位元組序列,在 check-in 時會被替換為 $Id$

filter

可以將 filter 屬性設定為字串值,該字串值命名在組態中指定的篩選驅動程式。

篩選驅動程式包含 clean 命令和 smudge 命令,兩者皆可保留為未指定。在 checkout 時,如果指定了 smudge 命令,則會將 blob 物件從其標準輸入饋入該命令,並且其標準輸出會用於更新工作樹檔案。類似地,clean 命令會用於在 checkin 時轉換工作樹檔案的內容。預設情況下,這些命令只會處理單一 blob 並終止。如果在 clean 和/或 smudge 篩選器中使用了長時間執行的 process 篩選器,則 Git 可以針對單一 Git 命令的整個生命週期,使用單一篩選器命令呼叫來處理所有 blob,例如 git add --all。如果組態了長時間執行的 process 篩選器,則它始終優先於組態的單一 blob 篩選器。有關與 process 篩選器通訊所使用協定的描述,請參閱以下章節。

內容篩選的一個用途是將內容整理成更方便平台、檔案系統和使用者使用的形式。對於此操作模式,關鍵短語是「更方便」,而不是「將無法使用的東西變成可用」。換句話說,意圖是,如果有人取消設定篩選驅動程式定義,或者沒有適當的篩選程式,則該專案仍然可以使用。

內容篩選的另一個用途是儲存無法直接在儲存庫中使用的內容(例如,引用儲存在 Git 外部的真實內容的 UUID,或加密的內容),並在 checkout 時將其轉換為可用的形式(例如,下載外部內容,或解密加密的內容)。

這兩個篩選器的行為不同,預設情況下,篩選器會被視為前者,將內容整理成更方便的形式。組態中缺少篩選驅動程式定義,或篩選驅動程式以非零狀態結束,都不是錯誤,而是使篩選器成為無操作的 passthru。

您可以透過將 filter.<driver>.required 組態變數設定為 true 來宣告篩選器將無法使用的內容轉換為可用的內容。

注意:每當 clean 篩選器變更時,應重新標準化儲存庫:$ git add --renormalize .

例如,在 .gitattributes 中,您將為路徑指派 filter 屬性。

*.c	filter=indent

然後,您會在 .git/config 中定義「filter.indent.clean」和「filter.indent.smudge」組態,以指定一對命令,以便在簽入原始檔時(執行「clean」)以及在簽出原始檔時修改 C 程式的內容(不進行變更,因為該命令是「cat」)。

[filter "indent"]
	clean = indent
	smudge = cat

為了獲得最佳結果,如果 clean 執行兩次,則不應進一步變更其輸出(「clean→clean」應等同於「clean」),並且多個 smudge 命令不應變更 clean 的輸出(「smudge→smudge→clean」應等同於「clean」)。請參閱下方的合併章節。

「indent」篩選器在這方面表現良好:它不會修改已正確縮排的輸入。在這種情況下,缺少 smudge 篩選器表示 clean 篩選器必須接受其自己的輸出,而不會修改它。

如果篩選器必須成功才能使儲存的內容可用,則可以在組態中宣告該篩選器是 required

[filter "crypt"]
	clean = openssl enc ...
	smudge = openssl enc -d ...
	required

篩選器命令列上的序列 "%f" 會被替換為篩選器正在處理的檔案名稱。篩選器可能會在關鍵字替換中使用此名稱。例如

[filter "p4"]
	clean = git-p4-filter --clean %f
	smudge = git-p4-filter --smudge %f

請注意,"%f" 是正在處理的路徑名稱。根據篩選的版本,磁碟上的對應檔案可能不存在,或者可能具有不同的內容。因此,smudge 和 clean 命令不應嘗試存取磁碟上的檔案,而只能作為篩選器對標準輸入上提供給它們的內容進行操作。

長時間執行的篩選器程序

如果篩選器命令(字串值)是透過 filter.<driver>.process 定義的,則 Git 可以針對單一 Git 命令的整個生命週期,使用單一篩選器呼叫來處理所有 blob。這是透過使用長時間執行的程序協定來實現的(如 technical/long-running-process-protocol.txt 中所述)。

當 Git 遇到第一個需要 clean 或 smudge 的檔案時,它會啟動篩選器並執行交握。在交握中,Git 發送的歡迎訊息是「git-filter-client」,僅支援版本 2,且支援的功能為「clean」、「smudge」和「delay」。

之後,Git 會傳送以清除封包終止的「key=value」配對清單。該清單至少會包含篩選命令(根據支援的功能)和要篩選的檔案相對於儲存庫根目錄的路徑名稱。在清除封包之後,Git 會將內容分割成零個或多個 pkt-line 封包,並以清除封包終止內容。請注意,篩選器在收到內容和最終清除封包之前,不得傳送任何回應。另請注意,「key=value」配對的「value」可以包含「=」字元,而 key 永遠不會包含該字元。

packet:          git> command=smudge
packet:          git> pathname=path/testfile.dat
packet:          git> 0000
packet:          git> CONTENT
packet:          git> 0000

預期篩選器會以清除封包終止的「key=value」配對清單回應。如果篩選器沒有遇到問題,則該清單必須包含「success」狀態。在這些封包之後,預期篩選器會以零個或多個 pkt-line 封包傳送內容,並在最後以清除封包結尾。最後,預期會傳送以清除封包終止的第二個「key=value」配對清單。篩選器可以變更第二個清單中的狀態,或使用空清單保持狀態不變。請注意,無論如何,空清單都必須以清除封包終止。

packet:          git< status=success
packet:          git< 0000
packet:          git< SMUDGED_CONTENT
packet:          git< 0000
packet:          git< 0000  # empty list, keep "status=success" unchanged!

如果結果內容為空,則預期篩選器會以「success」狀態和清除封包回應,以表示空的內容。

packet:          git< status=success
packet:          git< 0000
packet:          git< 0000  # empty content!
packet:          git< 0000  # empty list, keep "status=success" unchanged!

如果篩選器無法或不想要處理內容,則預期會回應「error」狀態。

packet:          git< status=error
packet:          git< 0000

如果篩選器在處理過程中發生錯誤,則可以在(部分或完整)傳送內容後,傳送「error」狀態。

packet:          git< status=success
packet:          git< 0000
packet:          git< HALF_WRITTEN_ERRONEOUS_CONTENT
packet:          git< 0000
packet:          git< status=error
packet:          git< 0000

如果篩選器無法或不想要處理內容,以及 Git 程序生命週期內的任何未來內容,則預期在協定的任何時間點回應「abort」狀態。

packet:          git< status=abort
packet:          git< 0000

在設定「error」/「abort」狀態的情況下,Git 既不會停止也不會重新啟動篩選器程序。但是,Git 會根據 filter.<driver>.required 旗標設定其結束代碼,模擬 filter.<driver>.clean / filter.<driver>.smudge 機制的行為。

如果篩選器在通訊期間停止運作,或不遵守協定,則 Git 會停止篩選器程序,並在下一個需要處理的檔案重新啟動它。根據 filter.<driver>.required 旗標,Git 會將其解釋為錯誤。

延遲

如果篩選器支援「delay」功能,則 Git 可以在篩選器命令和路徑名稱之後傳送「can-delay」旗標。此旗標表示篩選器可以延遲篩選目前的 Blob(例如,補償網路延遲),方法是回應沒有內容,但有「delayed」狀態和刷新封包。

packet:          git> command=smudge
packet:          git> pathname=path/testfile.dat
packet:          git> can-delay=1
packet:          git> 0000
packet:          git> CONTENT
packet:          git> 0000
packet:          git< status=delayed
packet:          git< 0000

如果篩選器支援「delay」功能,則必須支援「list_available_blobs」命令。如果 Git 傳送此命令,則篩選器預期會傳回路徑名稱清單,代表先前延遲且現在可用的 Blob。該清單必須以刷新封包終止,接著是以刷新封包終止的「success」狀態。如果沒有延遲路徑的 Blob 可用,則篩選器預期會封鎖回應,直到至少有一個 Blob 可用。篩選器可以透過傳送空清單來告知 Git 它沒有更多延遲的 Blob。一旦篩選器回應空清單,Git 就會停止詢問。Git 此時未收到的所有 Blob 都會被視為遺失,並導致錯誤。

packet:          git> command=list_available_blobs
packet:          git> 0000
packet:          git< pathname=path/testfile.dat
packet:          git< pathname=path/otherfile.dat
packet:          git< 0000
packet:          git< status=success
packet:          git< 0000

Git 收到路徑名稱後,會再次要求對應的 Blob。這些請求包含路徑名稱和一個空的內容區段。篩選器預期會以上述說明的方式,以通常方式回應塗抹過的內容。

packet:          git> command=smudge
packet:          git> pathname=path/testfile.dat
packet:          git> 0000
packet:          git> 0000  # empty content!
packet:          git< status=success
packet:          git< 0000
packet:          git< SMUDGED_CONTENT
packet:          git< 0000
packet:          git< 0000  # empty list, keep "status=success" unchanged!

範例

在 Git 核心儲存庫中的 contrib/long-running-filter/example.pl 中可以找到長時間執行篩選器的示範實作。如果您開發自己的長時間執行篩選器程序,則 GIT_TRACE_PACKET 環境變數對於偵錯非常有用(請參閱 git[1])。

請注意,您不能將現有的 filter.<driver>.cleanfilter.<driver>.smudge 命令與 filter.<driver>.process 一起使用,因為前兩者使用與後者不同的程序間通訊協定。

簽入/簽出屬性之間的互動

在簽入程式碼路徑中,工作樹檔案會先使用 filter 驅動程式(如果已指定且定義了對應的驅動程式)進行轉換,然後結果會使用 ident (如果已指定)進行處理,最後再使用 text (如果已指定且適用)進行處理。

在簽出程式碼路徑中,Blob 內容會先使用 text 轉換,然後傳遞給 identfilter

合併具有不同簽入/簽出屬性的分支

如果您已為檔案新增屬性,導致該檔案的標準儲存庫格式發生變更,例如新增 clean/smudge 篩選器或 text/eol/ident 屬性,則合併任何未設定屬性的內容通常會導致合併衝突。

為了避免這些不必要的合併衝突,可以透過設定 merge.renormalize 組態變數,告知 Git 在解析三向合併時執行檔案所有三個階段的虛擬簽出和簽入。這可以防止因簽入轉換而造成的變更,在轉換後的檔案與未轉換的檔案合併時產生虛假的合併衝突。

只要「smudge→clean」的結果與「clean」的結果相同(即使是對已塗抹的檔案),此策略也會自動解決所有與篩選器相關的衝突。不以這種方式運作的篩選器可能會導致必須手動解決的其他合併衝突。

產生差異文字

diff

diff 屬性會影響 Git 如何為特定檔案產生差異。它可以告知 Git 是否要為路徑產生文字修補程式,或是將路徑視為二進位檔案。它也可以影響在 hunk 標頭 @@ -k,l +n,m @@ 行中顯示的行,告知 Git 使用外部命令產生差異,或要求 Git 在產生差異之前將二進位檔案轉換為文字格式。

設定

設定了 diff 屬性的路徑會被視為文字,即使它們包含通常不會出現在文字檔案中的位元組值(例如 NUL)。

取消設定

取消設定了 diff 屬性的路徑會產生 Binary files differ (如果啟用了二進位修補程式,則會產生二進位修補程式)。

未指定

未指定 diff 屬性的路徑會先檢查其內容,如果看起來像文字且小於 core.bigFileThreshold,則會被視為文字。否則會產生 Binary files differ

字串

差異會使用指定的差異驅動程式顯示。每個驅動程式都可以指定一個或多個選項,如下一節所述。差異驅動程式「foo」的選項由 Git 組態檔案的「diff.foo」區段中的組態變數定義。

定義外部差異驅動程式

差異驅動程式的定義是在 gitconfig 中完成的,而不是 gitattributes 檔案中,因此嚴格來說,本手冊頁面不適合討論它。但是...

若要定義外部差異驅動程式 jcdiff,請在您的 $GIT_DIR/config 檔案(或 $HOME/.gitconfig 檔案)中新增一個區段,如下所示

[diff "jcdiff"]
	command = j-c-diff

當 Git 需要為設定為 jcdiffdiff 屬性路徑顯示差異時,它會使用上述組態呼叫您指定的命令,即 j-c-diff,並帶有 7 個參數,就像呼叫 GIT_EXTERNAL_DIFF 程式一樣。如需詳細資訊,請參閱 git[1]

如果程式能夠忽略某些變更(類似於 git diff --ignore-space-change),也請將選項 trustExitCode 設定為 true。如果它發現重大變更,則預期會傳回結束代碼 1,如果沒有則傳回 0。

設定內部差異演算法

可以透過 diff.algorithm 組態金鑰設定差異演算法,但有時為每個路徑設定差異演算法可能會很有用。例如,可能想要對 .json 檔案使用 minimal 差異演算法,對 .c 檔案使用 histogram,依此類推,而無需每次都透過命令列傳遞演算法。

首先,在 .gitattributes 中,為路徑指派 diff 屬性。

*.json diff=<name>

然後,定義「diff.<name>.algorithm」組態以指定差異演算法,從 myerspatienceminimalhistogram 中選擇。

[diff "<name>"]
  algorithm = histogram

此差異演算法適用於使用者面對的差異輸出,例如 git-diff(1)、git-show(1),也用於 --stat 輸出。合併機制不會使用透過此方法設定的差異演算法。

注意
如果為具有 diff=<name> 屬性的路徑定義了 diff.<name>.command,則會作為外部差異驅動程式執行(請參閱上文),而新增 diff.<name>.algorithm 無效,因為該演算法不會傳遞給外部差異驅動程式。

定義自訂 hunk 標頭

文字差異輸出中的每個變更群組(稱為「hunk」)都以以下形式的行作為前置詞

@@ -k,l +n,m @@ TEXT

這稱為hunk 標頭。「TEXT」部分預設是以字母、底線或錢字符號開頭的行;這符合 GNU diff -p 輸出使用的內容。但是,此預設選取不適用於某些內容,您可以使用自訂模式進行選取。

首先,在 .gitattributes 中,您會為路徑指派 diff 屬性。

*.tex	diff=tex

然後,您會定義「diff.tex.xfuncname」組態,以指定符合您希望顯示為 hunk 標頭「TEXT」的行的正規表示式。在您的 $GIT_DIR/config 檔案(或 $HOME/.gitconfig 檔案)中新增一個區段,如下所示

[diff "tex"]
	xfuncname = "^(\\\\(sub)*section\\{.*)$"

注意。組態檔案剖析器會吃掉單層反斜線,因此您需要將反斜線加倍;上面的模式會選取以反斜線開頭,以及零個或多個出現的 sub,接著是 section,然後是左大括號,直到行尾的行。

有一些內建模式可以讓此操作更容易,而 tex 就是其中之一,因此您不必在組態檔案中寫入上述內容(您仍然需要透過屬性機制,透過 .gitattributes 啟用此功能)。可以使用以下內建模式

  • ada 適用於 Ada 語言的原始碼。

  • bash 適用於 Bourne-Again SHell 語言的原始碼。涵蓋 POSIX shell 函式定義的超集。

  • bibtex 適用於具有 BibTeX 編碼參考的檔案。

  • cpp 適用於 C 和 C++ 語言的原始碼。

  • csharp 適用於 C# 語言的原始碼。

  • css 適用於階層式樣式表。

  • dts 適用於 devicetree (DTS) 檔案。

  • elixir 適用於 Elixir 語言的原始碼。

  • fortran 適用於 Fortran 語言的原始碼。

  • fountain 適用於 Fountain 文件。

  • golang 適用於 Go 語言的原始碼。

  • html 適用於 HTML/XHTML 文件。

  • java 適用於 Java 語言的原始碼。

  • kotlin 適用於 Kotlin 語言的原始碼。

  • markdown 適用於 Markdown 文件。

  • matlab 適用於 MATLAB 和 Octave 語言的原始碼。

  • objc 適用於 Objective-C 語言的原始碼。

  • pascal 適用於 Pascal/Delphi 語言的原始碼。

  • perl 適用於 Perl 語言的原始碼。

  • php 適用於 PHP 語言的原始碼。

  • python 適用於 Python 語言的原始碼。

  • ruby 適用於 Ruby 語言的原始碼。

  • rust 適用於 Rust 語言的原始碼。

  • scheme 適用於 Scheme 語言的原始碼。

  • tex 適用於 LaTeX 文件的原始碼。

自訂單字差異

您可以使用 git diff --word-diff,並在 "diff.*.wordRegex" 設定變數中指定適當的正規表達式,來自訂行中單字的分隔規則。例如,在 TeX 中,反斜線後接一連串字母會構成一個指令,但數個此類指令可以連續執行,中間不需要有空白。若要分隔它們,請在您的 $GIT_DIR/config 檔案(或 $HOME/.gitconfig 檔案)中使用類似以下的正規表達式:

[diff "tex"]
	wordRegex = "\\\\[a-zA-Z]+|[{}]|\\\\.|[^\\{}[:space:]]+"

內建模式已為前一節中列出的所有語言提供。

對二進位檔案執行文字差異比較

有時,您可能希望看到某些二進位檔案的文字轉換版本的差異比較。例如,文字處理器文件可以轉換為 ASCII 文字表示法,並顯示文字差異。即使這種轉換會遺失某些資訊,產生的差異比較仍有助於人類檢視(但無法直接套用)。

textconv 設定選項用於定義執行此類轉換的程式。該程式應接受單一引數,即要轉換的檔案名稱,並在 stdout 上產生結果文字。

例如,若要顯示檔案的 exif 資訊差異,而不是二進位資訊(假設您已安裝 exif 工具),請將以下區段新增至您的 $GIT_DIR/config 檔案(或 $HOME/.gitconfig 檔案):

[diff "jpg"]
	textconv = exif
注意
文字轉換通常是單向轉換;在此範例中,我們遺失了實際的影像內容,而只專注於文字資料。這表示由 textconv 產生的差異適合套用。因此,只有 git diffgit log 系列指令(即 log、whatchanged、show)會執行文字轉換。git format-patch 永遠不會產生此輸出。如果您想將二進位檔案的文字轉換差異傳送給某人(例如,因為它能快速傳達您所做的變更),您應該單獨產生它,並將其作為註解傳送,除了您可能傳送的通常二進位差異之外。

由於文字轉換可能會很慢,尤其是在使用 git log -p 執行大量轉換時,Git 提供了一種機制來快取輸出,並在未來的差異比較中使用。若要啟用快取,請在您的 diff 驅動程式的設定中設定 "cachetextconv" 變數。例如:

[diff "jpg"]
	textconv = exif
	cachetextconv = true

這會無限期地快取對每個 blob 執行 "exif" 的結果。如果您變更 diff 驅動程式的 textconv 設定變數,Git 會自動使快取項目失效,並重新執行 textconv 篩選器。如果您想要手動使快取失效(例如,因為您的 "exif" 版本已更新,現在產生更好的輸出),您可以使用 git update-ref -d refs/notes/textconv/jpg 手動移除快取(其中 "jpg" 是 diff 驅動程式的名稱,如上述範例所示)。

選擇 textconv 與外部差異比較

如果您想顯示儲存庫中二進位或特殊格式 blob 之間的差異,您可以選擇使用外部差異比較指令,或使用 textconv 將它們轉換為可進行差異比較的文字格式。您選擇哪種方法取決於您的具體情況。

使用外部差異比較指令的優點是彈性。您不受限於尋找以行為導向的變更,也不需要輸出看起來像統一差異比較。您可以自由地以最適合您資料格式的方式尋找並報告變更。

相比之下,textconv 的限制要大得多。您將資料轉換為以行為導向的文字格式,而 Git 使用其常規差異比較工具來產生輸出。選擇此方法有幾個優點:

  1. 易於使用。編寫二進位到文字的轉換通常比執行自己的差異比較要簡單得多。在許多情況下,現有的程式可以用作 textconv 篩選器(例如,exif、odt2txt)。

  2. Git 差異比較功能。透過僅自行執行轉換步驟,您仍然可以使用 Git 的許多差異比較功能,包括色彩化、單字差異比較,以及合併的組合差異比較。

  3. 快取。Textconv 快取可以加快重複差異比較的速度,例如您可能會透過執行 git log -p 觸發的比較。

將檔案標記為二進位

Git 通常會透過檢查內容的開頭來正確猜測 blob 是否包含文字或二進位資料。但是,有時您可能想要覆寫其決策,因為 blob 在檔案稍後包含二進位資料,或者因為內容雖然技術上由文字字元組成,但對於人類讀者而言是不透明的。例如,許多 postscript 檔案僅包含 ASCII 字元,但會產生雜亂且無意義的差異比較。

將檔案標記為二進位最簡單的方法是在 .gitattributes 檔案中取消設定 diff 屬性:

*.ps -diff

這會導致 Git 產生 Binary files differ (如果啟用二進位修補程式,則會產生二進位修補程式),而不是常規差異比較。

但是,您可能還想指定其他 diff 驅動程式屬性。例如,您可能想使用 textconv 將 postscript 檔案轉換為 ASCII 表示法以供人類檢視,但在其他情況下將它們視為二進位檔案。您不能同時指定 -diffdiff=ps 屬性。解決方案是使用 diff.*.binary 設定選項:

[diff "ps"]
  textconv = ps2ascii
  binary = true

執行三向合併

merge

當在 git merge 及其他指令(如 git revertgit cherry-pick)期間需要檔案層級合併時,merge 屬性會影響如何合併檔案的三個版本。

設定

內建的三向合併驅動程式用於以類似於 RCS 套件的 merge 指令的方式合併內容。這適用於普通文字檔案。

取消設定

從目前分支取得版本作為暫定合併結果,並宣告合併發生衝突。這適用於沒有明確定義的合併語義的二進位檔案。

未指定

預設情況下,這會使用與設定 merge 屬性時相同的內建三向合併驅動程式。但是,merge.default 設定變數可以命名不同的合併驅動程式,以用於未指定 merge 屬性的路徑。

字串

使用指定的自訂合併驅動程式執行三向合併。可以透過請求 "text" 驅動程式來明確指定內建的三向合併驅動程式;可以使用 "binary" 請求內建的「採用目前分支」驅動程式。

內建合併驅動程式

有一些已定義的內建低階合併驅動程式,可以透過 merge 屬性請求。

text

用於文字檔案的常見三向檔案層級合併。衝突區域會以衝突標記 <<<<<<<=======>>>>>>> 標記。您分支中的版本會出現在 ======= 標記之前,而合併分支中的版本會出現在 ======= 標記之後。

binary

將您分支中的版本保留在工作樹中,但將路徑保留在衝突狀態,以供使用者解決。

union

對文字檔案執行三向檔案層級合併,但採用兩個版本的行,而不是保留衝突標記。這往往會使產生的檔案中新增的行以隨機順序排列,使用者應驗證結果。如果您不了解其含義,請勿使用此選項。

定義自訂合併驅動程式

合併驅動程式的定義在 .git/config 檔案中完成,而不是在 gitattributes 檔案中,因此嚴格來說,此手冊頁面不應該討論它。但是…​

若要定義自訂合併驅動程式 filfre,請將區段新增至您的 $GIT_DIR/config 檔案(或 $HOME/.gitconfig 檔案),如下所示:

[merge "filfre"]
	name = feel-free merge driver
	driver = filfre %O %A %B %L %P
	recursive = binary

merge.*.name 變數會為驅動程式提供人類可讀的名稱。

merge.*.driver 變數的值用於建構要執行的指令,以處理共同祖先的版本 (%O)、目前版本 (%A) 和其他分支的版本 (%B)。當建構命令列時,這三個權杖會取代為保存這些版本內容的臨時檔案名稱。此外,%L 將取代為衝突標記大小(請參閱下文)。

合併驅動程式預期會將合併結果保留在使用 %A 命名的檔案中,方法是覆寫它,並在它設法順利合併它們時以零狀態結束,或者在發生衝突時以非零狀態結束。當驅動程式崩潰時(例如,被 SEGV 終止),它預期會以高於 128 的非零狀態結束,在這種情況下,合併會導致失敗(與產生衝突不同)。

當呼叫合併驅動程式以處理共同祖先之間的內部合併時(當有多個共同祖先時),merge.*.recursive 變數會指定要使用的其他合併驅動程式。當未指定時,驅動程式本身會用於內部合併和最終合併。

合併驅動程式可以透過佔位符 %P 了解合併結果將儲存的路徑名稱。用於共同祖先、本機標頭和其他標頭的衝突標籤可以分別使用 %S%X 和 '%Y` 來傳遞。

conflict-marker-size

此屬性控制在衝突合併期間保留在工作樹檔案中的衝突標記的長度。只有正整數才有意義的效果。

例如,當合併檔案 Documentation/git-merge.txt 時發生衝突時,可以使用 .gitattributes 中的這一行來告知合併機制保留更長的衝突標記(而不是通常的 7 個字元長)。

Documentation/git-merge.txt	conflict-marker-size=32

檢查空白錯誤

whitespace

core.whitespace 設定變數可讓您定義 diffapply 應將哪些視為專案中所有路徑的空白錯誤(請參閱 git-config[1])。此屬性可讓您對每個路徑進行更精細的控制。

設定

注意 Git 已知的所有潛在空白錯誤類型。索引標籤寬度取自 core.whitespace 設定變數的值。

取消設定

不要將任何內容視為錯誤。

未指定

使用 core.whitespace 設定變數的值來決定要將哪些內容視為錯誤。

字串

指定以逗號分隔的常見空白問題清單,以與 core.whitespace 設定變數相同的格式來注意。

建立封存檔

export-ignore

具有 export-ignore 屬性的檔案和目錄不會新增至封存檔。

export-subst

如果檔案設定了 export-subst 屬性,當將此檔案加入封存時,Git 會展開數個佔位符。展開的行為取決於 commit ID 是否存在,也就是說,如果 git-archive[1] 接收的是樹狀結構而非 commit 或標籤,則不會進行任何替換。這些佔位符與 git-log[1]--pretty=format: 選項相同,只是它們需要像這樣被包裹:$Format:佔位符$ 在檔案中。例如,字串 $Format:%H$ 會被替換為 commit 的雜湊值。然而,為了避免阻斷服務攻擊,每個封存只會展開一個 %(describe) 佔位符。

打包物件

delta

對於路徑設定為 delta 屬性為 false 的 blob,不會嘗試使用差異壓縮。

在 GUI 工具中檢視檔案

encoding

此屬性的值指定 GUI 工具 (例如 gitk[1]git-gui[1]) 應使用的字元編碼,以顯示相關檔案的內容。請注意,由於效能考量,gitk[1] 不會使用此屬性,除非您在選項中手動啟用每個檔案的編碼。

如果未設定此屬性或具有無效的值,則會改用 gui.encoding 設定變數的值(請參閱 git-config[1])。

使用巨集屬性

您不希望對您追蹤的任何二進位檔案套用任何行尾轉換,也不希望產生文字差異。您需要指定例如:

*.jpg -text -diff

但當您有許多屬性時,這可能會變得繁瑣。使用巨集屬性,您可以定義一個屬性,當設定時,它會同時設定或取消設定多個其他屬性。系統知道一個內建的巨集屬性 binary

*.jpg binary

設定 "binary" 屬性也會像上面一樣取消設定 "text" 和 "diff" 屬性。請注意,巨集屬性只能「設定」,但設定一個巨集屬性可能會產生設定或取消設定其他屬性的效果,甚至使其他屬性回到「未指定」狀態。

定義巨集屬性

自訂巨集屬性只能在最上層的 gitattributes 檔案中定義($GIT_DIR/info/attributes,工作樹最上層的 .gitattributes 檔案,或全域或系統範圍的 gitattributes 檔案),而不能在工作樹子目錄中的 .gitattributes 檔案中定義。內建的巨集屬性 "binary" 等效於

[attr]binary -diff -merge -text

注意事項

當存取工作樹中的 .gitattributes 檔案時,Git 不會追蹤符號連結。這樣可以確保當從索引或樹狀結構存取檔案時,與從檔案系統存取時的行為保持一致。

範例

如果您有以下三個 gitattributes 檔案

(in $GIT_DIR/info/attributes)

a*	foo !bar -baz

(in .gitattributes)
abc	foo bar baz

(in t/.gitattributes)
ab*	merge=filfre
abc	-foo -bar
*.c	frotz

路徑 t/abc 的屬性計算方式如下

  1. 透過檢查 t/.gitattributes(與相關路徑位於同一目錄),Git 發現第一行符合。merge 屬性被設定。它還發現第二行符合,並且 foobar 屬性被取消設定。

  2. 然後,它檢查 .gitattributes(位於父目錄中),並發現第一行符合,但 t/.gitattributes 檔案已經決定了 mergefoobar 屬性應該如何賦予此路徑,因此它保留 foobar 為未設定。baz 屬性被設定。

  3. 最後,它檢查 $GIT_DIR/info/attributes。此檔案用於覆蓋樹狀結構中的設定。第一行符合,且 foo 被設定,bar 回復到未指定狀態,且 baz 被取消設定。

結果,t/abc 的屬性指定變為

foo	set to true
bar	unspecified
baz	set to false
merge	set to string value "filfre"
frotz	unspecified

另請參閱

GIT

屬於 git[1] 套件的一部分

scroll-to-top