簡體中文 ▾ 主題 ▾ 最新版本 ▾ gitattributes 最後更新於 2.50.0

名稱

gitattributes - 為每個路徑定義屬性

概要

$GIT_DIR/info/attributes, .gitattributes

描述

一個 gitattributes 檔案是一個簡單的文字檔案,它為路徑名指定 屬性

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

pattern attr1 attr2 ...

即,一個模式後面跟著一個屬性列表,由空格分隔。前導和尾隨空格被忽略。以#開頭的行被忽略。以雙引號開頭的模式以 C 風格引用。當模式匹配到相關路徑時,該行中列出的屬性將被賦予該路徑。

對於給定路徑,每個屬性可以處於以下狀態之一

設定

路徑具有特殊值“true”的屬性;這透過在屬性列表中只列出屬性名稱來指定。

未設定

路徑具有特殊值“false”的屬性;這透過在屬性列表中列出屬性名稱並在其前面加上一個破折號 - 來指定。

設定為一個值

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

未指定

沒有模式匹配路徑,也沒有說明路徑是否具有該屬性,該路徑的屬性被認為是未指定的。

當多個模式匹配同一路徑時,後來的行會覆蓋早前的行。這種覆蓋是針對每個屬性進行的。

模式匹配路徑的規則與 .gitignore 檔案中的規則相同(參見 gitignore[5]),但有一些例外

  • 負模式是被禁止的

  • 匹配目錄的模式不會遞迴地匹配該目錄內的路徑(因此,在 attributes 檔案中使用尾隨斜槓 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 檔案中。

有時您需要將路徑的某個屬性設定覆蓋為 未指定 狀態。這可以透過在屬性名稱前加上一個感嘆號 ! 來實現。

保留的 BUILTIN_* 屬性

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。相反,當檔案從索引複製到工作目錄時,其行結束符可能會從 LF 轉換為 CRLF,具體取決於 eol 屬性、Git 配置和平臺(參見下面 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 本身不會觸及工作樹中的檔案,但下一次檢出會,因此會觸發安全機制;

  • git apply 更新帶有補丁的文字檔案會觸及工作樹中的檔案,但該操作是關於文字檔案的,CRLF 轉換是為了修復行結束符不一致,因此不會觸發安全機制;

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

working-tree-encoding

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

在這些情況下,您可以使用 working-tree-encoding 屬性告訴 Git 工作目錄中檔案的編碼。如果一個帶有此屬性的檔案被新增到 Git,那麼 Git 會將內容從指定的編碼重新編碼為 UTF-8。最後,Git 將 UTF-8 編碼的內容儲存在其內部資料結構中(稱為“索引”)。在檢出時,內容會被重新編碼回指定的編碼。

請注意,使用 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 支援的客戶端將以 UTF-8 編碼的檔案檢出 foo.ps1。這通常會給該檔案的使用者帶來麻煩。

    如果不支援 working-tree-encoding 屬性的 Git 客戶端添加了一個新檔案 bar.ps1,那麼 bar.ps1 將“原樣”儲存在內部(在此示例中可能為 UTF-16)。支援 working-tree-encoding 的客戶端會將內部內容解釋為 UTF-8,並在檢出時嘗試將其轉換為 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 會在檢出時將 blob 物件中的 $Id$ 替換為 $Id:,後跟 40 個字元的十六進位制 blob 物件名稱,再後跟一個美元符號 $。工作樹檔案中以 $Id: 開頭並以 $ 結尾的任何位元組序列在檢入時都會被替換為 $Id$

filter

可以將 filter 屬性設定為一個字串值,該值命名了配置中指定的過濾器驅動程式。

一個過濾器驅動程式由一個 clean 命令和一個 smudge 命令組成,其中任何一個都可以不指定。在檢出時,如果指定了 smudge 命令,則將 blob 物件作為其標準輸入,並使用其標準輸出來更新工作樹檔案。類似地,clean 命令用於在檢入時轉換工作樹檔案的內容。預設情況下,這些命令只處理單個 blob 並終止。如果使用長時間執行的 process 過濾器代替 clean 和/或 smudge 過濾器,那麼 Git 可以透過一次過濾器命令呼叫處理所有 blob,該呼叫持續單個 Git 命令的整個生命週期,例如 git add --all。如果配置了長時間執行的 process 過濾器,則它始終優先於配置的單個 blob 過濾器。有關與 process 過濾器通訊所用協議的描述,請參閱以下部分。

內容過濾的一種用途是,將內容整理成對平臺、檔案系統和使用者來說更方便使用的形式。對於這種操作模式,關鍵短語是“更方便”,而不是“將不可用的東西變成可用”。換句話說,其目的是,如果有人取消設定過濾器驅動程式定義,或者沒有合適的過濾器程式,專案仍然應該可用。

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

這兩種過濾器行為不同,預設情況下,過濾器被視為前者,將內容整理成更方便的形式。配置中缺少過濾器驅動程式定義,或者過濾器驅動程式以非零狀態退出,這不是錯誤,而是使過濾器成為無操作的直通。

您可以宣告過濾器透過將 filter.<driver>.required 配置變數設定為 true 來將內容轉換為自身不可用的可用內容。

注意:每當 clean 過濾器更改時,倉庫都應重新規範化:$ git add --renormalize .

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

*.c	filter=indent

然後,您將在 .git/config 中定義 "filter.indent.clean" 和 "filter.indent.smudge" 配置,以指定一對命令來修改 C 程式的內容,當原始碼檔案被檢入時(執行 "clean")和檢出時(不進行更改,因為命令是 "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。這是透過使用長時間執行程序協議(在 Documentation/technical/long-running-process-protocol.adoc 中描述)實現的。

當 Git 遇到第一個需要清理或塗抹的檔案時,它會啟動過濾器並執行握手。在握手中,Git 傳送的歡迎訊息是“git-filter-client”,只支援版本 2,支援的功能是“clean”、“smudge”和“delay”。

之後,Git 會發送一個以 flush 包終止的“key=value”對列表。該列表將至少包含過濾器命令(基於支援的功能)以及相對於倉庫根目錄的檔案路徑。緊接著 flush 包,Git 會發送零個或多個 pkt-line 包以及一個 flush 包來終止內容。請注意,在收到內容和最終的 flush 包之前,過濾器不得傳送任何響應。另請注意,“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”對列表響應,並以 flush 包終止。如果過濾器沒有遇到問題,則該列表必須包含“success”狀態。緊接著這些包之後,過濾器應以零個或多個 pkt-line 包傳送內容,並在末尾傳送一個 flush 包。最後,應期望收到以 flush 包終止的第二個“key=value”對列表。過濾器可以在第二個列表中更改狀態,或透過空列表保持狀態不變。請注意,無論如何,空列表也必須以 flush 包終止。

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

如果結果內容為空,則過濾器應以“success”狀態和 flush 包響應,以表示內容為空。

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

Git 不會因為設定了“error”/“abort”狀態而停止或重新啟動過濾器程序。但是,Git 會根據 filter.<driver>.required 標誌設定其退出程式碼,模仿 filter.<driver>.clean / filter.<driver>.smudge 機制的行為。

如果在通訊過程中過濾器死亡或不遵守協議,那麼 Git 將停止過濾器程序,並在下一個需要處理的檔案時重新啟動它。根據 filter.<driver>.required 標誌,Git 會將其解釋為錯誤。

延遲

如果過濾器支援“delay”功能,那麼 Git 可以在過濾器命令和路徑名之後傳送“can-delay”標誌。此標誌表示過濾器可以延遲過濾當前 blob(例如,為了補償網路延遲),透過不響應內容但響應“delayed”狀態和一個 flush 包來完成。

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。該列表必須以一個 flush 包終止,後跟一個“success”狀態,該狀態也以一個 flush 包終止。如果延遲路徑的 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 轉換,然後是 ident,並提供給 filter

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

如果您向檔案添加了導致該檔案規範倉庫格式更改的屬性,例如新增 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 屬性未指定,Git 首先檢查其內容,如果看起來是文字且小於 core.bigFileThreshold,則將其視為文字。否則,它將生成 Binary files differ

字串

差異使用指定的差異驅動程式顯示。每個驅動程式可以指定一個或多個選項,如下節所述。差異驅動程式“foo”的選項由 Git 配置檔案中“diff.foo”部分的配置變數定義。

定義外部差異驅動程式

差異驅動程式的定義是在 gitconfig 中完成的,而不是在 gitattributes 檔案中,所以嚴格來說,本手冊頁談論它是不對的。然而……

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

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

當 Git 需要向您顯示 diff 屬性設定為 jcdiff 的路徑的差異時,它會呼叫您透過上述配置指定的命令,即 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”)都以以下形式的行作為字首

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

這被稱為 hunk header(塊頭)。“TEXT”部分預設是以字母、下劃線或美元符號開頭的行;這與 GNU diff -p 輸出使用的內容匹配。然而,此預設選擇不適用於某些內容,您可以使用自定義模式進行選擇。

首先,在 .gitattributes 中,您將為路徑分配 diff 屬性。

*.tex	diff=tex

然後,您將定義 "diff.tex.xfuncname" 配置以指定一個正則表示式,該正則表示式匹配您希望作為塊頭“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 適用於裝置樹(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 文件原始碼。

自定義詞差異

您可以透過在“diff.*.wordRegex”配置變數中指定合適的正則表示式來定製 git diff --word-diff 用於將一行拆分為單詞的規則。例如,在 TeX 中,反斜槓後跟字母序列構成一個命令,但幾個這樣的命令可以連續執行而無需中間空格。要將它們分開,請在您的 $GIT_DIR/config 檔案(或 $HOME/.gitconfig 檔案)中使用如下正則表示式

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

上一節中列出的所有語言都提供了內建模式。

執行二進位制檔案的文字差異

有時,需要檢視某些二進位制檔案文字轉換版本的差異。例如,文字處理文件可以轉換為 ASCII 文字表示,並顯示文字的差異。儘管這種轉換會丟失一些資訊,但生成的差異對於人類檢視很有用(但無法直接應用)。

textconv 配置選項用於定義執行此類轉換的程式。該程式應接受一個引數,即要轉換的檔名,並將結果文字輸出到標準輸出。

例如,要顯示檔案的 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 提供了一種機制來快取輸出並在未來的差異中使用它。要啟用快取,請在您的差異驅動程式的配置中設定“cachetextconv”變數。例如

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

這將無限期地快取對每個 blob 執行“exif”的結果。如果您更改差異驅動程式的 textconv 配置變數,Git 將自動使快取條目失效並重新執行 textconv 過濾器。如果您想手動使快取失效(例如,因為您的“exif”版本已更新,現在生成了更好的輸出),您可以使用 git update-ref -d refs/notes/textconv/jpg 手動刪除快取(其中“jpg”是差異驅動程式的名稱,如上面的示例所示)。

選擇 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(或二進位制補丁,如果啟用了二進位制補丁)而不是常規差異。

但是,可能還需要指定其他差異驅動程式屬性。例如,您可能希望使用 textconv 將 Postscript 檔案轉換為 ASCII 表示以供人工檢視,但否則將它們視為二進位制檔案。您不能同時指定 -diffdiff=ps 屬性。解決方案是使用 diff.*.binary 配置選項

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

執行三向合併

merge

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

設定

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

未設定

將當前分支的版本作為暫定的合併結果,並宣告合併存在衝突。這適用於沒有明確合併語義的二進位制檔案。

未指定

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

字串

使用指定的自定義合併驅動程式執行三向合併。內建的三向合併驅動程式可以透過請求“text”驅動程式顯式指定;內建的“take the current branch”驅動程式可以透過“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

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

例如,.gitattributes 中的這一行可用於告訴合併機制,當合並檔案 Documentation/git-merge.adoc 導致衝突時,留下更長(而不是通常的 7 個字元長)的衝突標記。

Documentation/git-merge.adoc	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 在將此檔案新增到存檔時將展開幾個佔位符。展開取決於提交 ID 的可用性,即,如果 git-archive[1] 已給定樹而不是提交或標籤,則不會進行替換。佔位符與 git-log[1]--pretty=format: 選項的佔位符相同,只是它們需要在檔案中像這樣包裝:$Format:PLACEHOLDERS$。例如,字串 $Format:%H$ 將被提交雜湊替換。但是,每個存檔只展開一個 %(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

注意事項

Git 在訪問工作樹中的 .gitattributes 檔案時不會跟隨符號連結。這使得從索引或樹(而不是從檔案系統)訪問檔案時的行為保持一致。

示例

如果您有這三個 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