設定和配置
獲取和建立專案
基本快照
分支與合併
共享和更新專案
檢查和比較
打補丁
除錯
電子郵件
外部系統
伺服器管理
指南
管理
底層命令
- 2.44.1 → 2.52.0 無更改
-
2.44.0
2024-02-23
- 2.43.1 → 2.43.7 無更改
-
2.43.0
2023-11-20
- 2.32.1 → 2.42.4 無更改
-
2.32.0
2021-06-06
- 2.31.1 → 2.31.8 無更改
-
2.31.0
2021-03-15
- 2.21.1 → 2.30.9 無更改
-
2.21.0
2019-02-24
- 2.13.7 → 2.20.5 無更改
-
2.12.5
2017-09-22
- 2.10.5 → 2.11.4 無更改
-
2.9.5
2017-07-30
- 2.5.6 → 2.8.6 無更改
-
2.4.12
2017-05-05
- 2.1.4 → 2.3.10 無更改
-
2.0.5
2014-12-17
描述
git diff-index, git diff-files, 和 git diff-tree 命令可以在顯示 diff 輸出之前,以非傳統的方式被告知操作它們找到的差異。這些操作統稱為“diffcore 轉換”。這篇簡短的說明描述了它們是什麼,以及如何使用它們來產生比傳統 diff 輸出更容易理解的 diff 輸出。
操作鏈
git diff-* 系列的工作原理是首先比較兩組檔案
-
git diff-index 比較“樹”物件和工作目錄(當未使用
--cached標誌時)或“樹”物件和索引檔案(當使用--cached標誌時)的內容; -
git diff-files 比較索引檔案和工作目錄的內容;
-
git diff-tree 比較兩個“樹”物件的內容;
在所有這些情況下,命令本身首先可以選擇性地透過其命令列上提供的任何路徑規範來限制這兩組檔案,並比較兩組檔案中對應的路徑。
路徑規範用於限制 diff 操作的範圍。它們會刪除指定路徑名集合之外的檔案對。例如,如果輸入的檔案對集合包括
:100644 100644 bcd1234... 0123456... M junkfile
但命令呼叫是 git diff-files myfile,那麼 junkfile 條目將從列表中刪除,因為只有“myfile”在考慮範圍內。
比較結果以一種類似於未啟用 -p 選項時的輸出格式,從這些命令傳遞給內部稱為“diffcore”的機制。例如:
in-place edit :100644 100644 bcd1234... 0123456... M file0 create :000000 100644 0000000... 1234567... A file4 delete :100644 000000 1234567... 0000000... D file5 unmerged :000000 000000 0000000... 0000000... U file6
diffcore 機制接收一個這樣的比較結果列表(每個結果被稱為“檔案對”,儘管此時每個都只涉及一個檔案),並將其轉換為另一個列表。目前有 5 種這樣的轉換:
-
diffcore-break
-
diffcore-rename
-
diffcore-merge-broken
-
diffcore-pickaxe
-
diffcore-order
-
diffcore-rotate
這些轉換按順序應用。git diff-* 命令找到的檔案對集合用作 diffcore-break 的輸入,diffcore-break 的輸出用作下一個轉換的輸入。最終結果然後傳遞給輸出例程,生成 diff-raw 格式(參見 git diff-* 命令的輸出格式部分)或 diff-patch 格式。
diffcore-break: 用於分割完全重寫
鏈中的第二個轉換是 diffcore-break,它由 git diff-* 命令的 -B 選項控制。它用於檢測代表“完全重寫”的檔案對,並將其分割成代表刪除和建立的兩個檔案對。例如,如果輸入包含此檔案對:
:100644 100644 bcd1234... 0123456... M file0
並且如果它檢測到檔案“file0”被完全重寫,它將更改為:
:100644 000000 bcd1234... 0000000... D file0 :000000 100644 0000000... 0123456... A file0
為了分割檔案對,diffcore-break 檢查修改前後文件內容之間的變化程度(即,在上面的例子中,內容 ID 為“bcd1234…”和“0123456…”的內容)。將原始內容的刪除量和新內容的插入量相加,如果超過“分割分數”,則將檔案對分割成兩個。分割分數預設為原始檔案和結果檔案(即,如果編輯使檔案變小,則使用結果的大小;如果編輯使檔案變長,則使用原始檔案的大小)中較小的那個的 50%,可以透過在“-B”選項後跟一個數字來定製(例如,“-B75”表示使用 75%)。
diffcore-rename: 用於檢測重新命名和複製
此轉換用於檢測重新命名和複製,並由 git diff-* 命令的 -M 選項(檢測重新命名)和 -C 選項(也檢測複製)控制。如果輸入包含這些檔案對:
:100644 000000 0123456... 0000000... D fileX :000000 100644 0000000... 0123456... A file0
並且已刪除檔案 fileX 的內容與新建立的檔案 file0 的內容足夠相似,則重新命名檢測會合並這些檔案對並建立:
:100644 100644 0123456... 0123456... R100 fileX file0
當使用“-C”選項時,已修改檔案的原始內容、已刪除檔案(以及未修改的檔案,如果使用了“--find-copies-harder”選項)被視為重新命名/複製操作的原始檔候選。如果輸入類似這些檔案對,它們涉及一個已修改的檔案 fileY 和一個新建立的檔案 file0:
:100644 100644 0123456... 1234567... M fileY :000000 100644 0000000... bcd3456... A file0
則比較 fileY 的原始內容和 file0 的結果內容,如果它們足夠相似,則將其更改為:
:100644 100644 0123456... 1234567... M fileY :100644 100644 0123456... bcd3456... C100 fileY file0
在重新命名和複製檢測中,都使用與 diffcore-break 中相同的“變化程度”演算法來確定兩個檔案是否“足夠相似”,並且可以透過在“-M”或“-C”選項後跟一個數字來定製相似度分數,使其不同於預設的 50%(例如,“-M8”表示使用 8/10 = 80%)。
請注意,當啟用重新命名檢測但停用複製和分割檢測時,重新命名檢測會新增一個初步步驟,首先檢查檔案是否在移動到不同目錄時保持檔名相同。如果存在一個新增到某個目錄的檔案,其內容與從另一個目錄中刪除的同名檔案足夠相似,它將把它們標記為重新命名,並從稍後的二次步驟(即逐個比較所有未匹配的檔案以查詢“最佳”匹配,由最高內容相似度決定)中排除它們。因此,例如,如果一個已刪除的 docs/ext.txt 和一個新新增的 docs/config/ext.txt 足夠相似,它們將被標記為重新命名,並阻止一個可能與已刪除的 docs/ext.txt 更相似的新新增的 docs/ext.md 在稍後的步驟中被視為重新命名目標。出於這個原因,初步的“匹配相同檔名”步驟使用稍高的閾值來將檔案對標記為重新命名,並停止考慮其他候選者以獲得更好的匹配。在此初步過程中,每個檔案最多執行一次比較;因此,如果在精確的重新命名檢測之後,目錄結構中仍然存在多個 ext.txt 檔案,則此初步步驟可能會跳過這些檔案。
注意。當使用“-C”選項和 --find-copies-harder 選項時,git diff-* 命令會將未修改的檔案對以及已修改的檔案對輸入到 diffcore 機制。這使得複製檢測器將未修改的檔案視為複製源候選,但代價是速度變慢。如果沒有 --find-copies-harder,git diff-* 命令只能在複製的檔案恰好在同一更改集中被修改時檢測到複製。
diffcore-merge-broken: 用於重新組合完全重寫
此轉換用於將 diffcore-break 分割但未被 diffcore-rename 轉換為重新命名/複製的檔案對重新合併為單個修改。當使用 diffcore-break 時,此操作始終執行。
為了重新組合分割的檔案對,它使用與 diffcore-break 和 diffcore-rename 不同的“變化程度”計算。它只計算原始檔案的刪除量,而不計算插入量。如果你從一個 100 行的文件中刪除了 10 行,即使你添加了 910 行新內容使其變成一個 1000 行的文件,你也沒有進行完全重寫。diffcore-break 會分割這種情況,以幫助 diffcore-rename 將這些檔案對視為重新命名/複製檢測的候選,但如果以這種方式分割的檔案對沒有與其他檔案對匹配以建立重新命名/複製,那麼此轉換會將它們合併回原始的“修改”。
“變化程度”引數可以從預設的 80% 進行調整(即,除非刪除了原始材料的 80% 以上,否則分割的檔案對將被合併回單個修改),方法是在 -B 選項中給出第二個數字,例如:
-
-B50/60(為 diffcore-break 提供 50% 的“分割分數”,為 diffcore-merge-broken 使用 60%)。
-
-B/60(與上面相同,因為 diffcore-break 預設為 50%)。
請注意,早期實現會將分割的檔案對保留為單獨的建立和刪除補丁。這是一個不必要的 hack,而最新的實現總是會將所有分割的檔案對合並回修改,但結果補丁的格式有所不同,以便在發生這種完全重寫時更易於審查,方法是顯示原始版本的全部內容(以 - 開頭),然後顯示新版本的全部內容(以 + 開頭)。
diffcore-pickaxe: 用於檢測指定字串的新增/刪除
此轉換將檔案對的集合限制為那些以某種方式在修改前和修改後影像之間更改了指定字串的檔案對。-S<block-of-text> 和 -G<regular-expression> 選項用於指定查詢這些字串的不同方式。
“-S<block-of-text>”檢測修改前和修改後影像中指定文字塊出現次數不同的檔案對。根據定義,它不會檢測檔案內部移動。此外,當更改集整體移動檔案而不影響感興趣的字串時,diffcore-rename 會像往常一樣啟動,而 -S 會省略檔案對(因為在該重新命名檢測的檔案對中該字串的出現次數沒有改變)。當與 --pickaxe-regex 一起使用時,將 <block-of-text> 視為擴充套件的 POSIX 正則表示式進行匹配,而不是文字字串。
“-G<regular-expression>”(助記符:grep)檢測其文字 diff 中包含與給定正則表示式匹配的新增或刪除行的檔案對。這意味著它會檢測檔案內部(或重新命名檢測認為的同一個檔案)的移動,這會產生噪音。實現是執行兩次 diff 並進行 grep,這可能非常耗時。為了加速,將忽略沒有文字轉換過濾器的二進位制檔案。
當 -S 或 -G 在沒有 --pickaxe-all 的情況下使用時,只有匹配各自標準的**檔案對**才會被保留在輸出中。當使用 --pickaxe-all 時,如果在更改集中至少有一個檔案對匹配各自的標準,則整個更改集都會被保留。這種行為旨在使審查更改集上下文中的更改更容易。
diffcore-order: 用於根據檔名對輸出進行排序
它用於根據使用者(或專案)的喜好重新排序檔案對,並由 git diff-* 命令的 -O 選項控制。
它接受一個文字檔案,檔案中的每一行都是一個 shell glob 模式。匹配檔案中較早一行的 glob 模式的檔案對將輸出在匹配較晚一行的檔案對之前,而未匹配任何 glob 模式的檔案對將最後輸出。
例如,核心 Git 的典型 orderfile 可能看起來像這樣:
README Makefile Documentation *.h *.c t
diffcore-rotate: 用於更改輸出開始的路徑
此轉換接受一個路徑名,並旋轉檔案對集合,使給定路徑名的檔案對排在第一位,可以選擇性地丟棄它之前的路徑。這用於實現 --skip-to 和 --rotate-to 選項。當指定的路徑名不在檔案對集合中時,會報錯,但在與“git log”系列命令一起使用時,報錯是沒有意義的,因為不能期望給定的路徑會被“git log”命令顯示的每一個提交所修改。出於這個原因,當與“git log”一起使用時,輸出將從與給定路徑名排序相同,或排序在其之後的第一個檔案對開始。
此轉換與 diffcore-order 結合使用可能會產生意外結果,因為當 diffcore-order 生效時,此轉換的輸入可能未排序。