git diff與linux diff的輸出格式之unified format

前言

前面有一篇文章《一個有些意思的項目–文件夾對比工具(一)》,裏面簡單講了下diff算法之–Myers算法。

既然是算法,就會有實現,比如git diff中有Myers的實現,git diff默認就是用了這個算法(也可以選擇其他算法);這個Myers算法,在linux的diff工具中也有實現;或者在一些js庫、java庫等都有實現。

另外,既然是算法,那就有輸入和輸出,如果大家都正確實現的話,按理說輸出格式也是能達成統一的。

接下來我們就看一下在各個軟件中的輸出格式。

git diff 輸出格式

樣例文件

附原文件內容,有興趣可以跟着試試。

image-20220803105718439

1111111111111111
2222222
333333333333333
4444444444444444444
55555555555
666666666
1111111111111111
2222222
333333333333333
4444444448878784444444444
insert1
55555555555
insert2
666666666
insert3

輸出格式

之前我以為只能在版本間對比文件差異,原來文件也是可以直接對比的,如下:

git  diff  test.txt test2.txt

image-20220803105847584

這裡可以看到,輸出中還包含了一些兩側沒變動的行,這是怎麼回事呢?主要是,默認情況下,會輸出差異行的上下文(即差異行的前面幾行和後面幾行,默認是三行)。

為了方便我們對比差異,我們先開啟一個選項,不展示上下文。

-U

–unified=

Generate diffs with lines of context instead of the usual three. Implies --patch.

開啟這個選項後,輸出如下:

image-20220803110257944

我們看的裏面有很多奇怪的符號,看得似懂非懂的,還有一些數字,也不知道啥意思,我們暫且不表,接下來,看看linux diff工具的輸出。

linux diff輸出格式

樣例文件

同上。

輸出格式(-U選項)

-U選項,在linux diff文檔里,是這個意思,我們指定 -U 0,就是0行上下文。

   -u, -U NUM, --unified[=NUM]
          output NUM (default 3) lines of unified context

image-20220803110548048

看起來,格式差不太多哈,不過內容不太一樣,這個先不用管,大家雖然都是同一個算法,但是部分工具會使用該算法的變體,所以輸出有些不同也是正常。

先聚焦於輸出格式即可。

默認輸出格式(不帶各類選項)

image-20220803111758903

看起來有點奇怪,輸出都沒有那些@@符號了,好像格式不同了,這是咋回事。

輸出格式(-c選項)

其實還有個選項,如下:

   -c, -C NUM, --context[=NUM]
          output NUM (default 3) lines of copied context

這個看起來像是上下文之類的,我們測試下:

image-20220803112018690

看上去和默認格式、-U格式都不同。

linux diff輸出的兩種格式(官方文檔)

具體內容都是來自於官方文檔://www.gnu.org/software/diffutils/manual/html_node/index.html

image-20220803111438170

這裡提到了兩種格式:

  • Context Format,即-c選項時,這種對比文件時,感覺不是很直觀;主要的場景是,用diff來生成代碼補丁,代碼差異行上下有上下文,方便補丁程序patch來進行差異代碼定位。

    The context output format shows several lines of context around the lines that differ. It is the standard format for distributing updates to source code.

  • Unified Format,即-u選項時,這種對比文件時,感覺還比較方便看;官方定義如下:

    The unified output format is a variation on the context format that is more compact because it omits redundant context lines.

    即該格式是context format的變體,因為省略了冗餘的上下文行,顯得更加緊湊。

unified format格式

簡介

不知道大家發現沒,git diff和linux diff(-u)時,產生的格式是一樣的,即unified format。

為什麼單獨講這個格式呢,因為我發現,有很多文件差異相關的第三方庫,不管是js、java啥的,產生的格式都是unified format。

而且,js中還有一個很廣泛的庫diff2html,是可以接收unified format格式的文件為輸入,渲染為美觀大方的html組件。

所以,在軟件生態來說,該格式已經是一個相對通用的交互格式了,類似於json、xml這樣的標準格式,所以,我們就講解它。

詳解

以如下輸出來舉例:

image-20220803114410981

unified format一開始就是文件列表,就是上圖的:

--- a/test.txt
+++ b/test2.txt

接下來就是差異段列表了,上圖一共兩個差異段,有點看不懂?那我們再看看樣例文件在beyond compare中的對比效果。

image-20220803105718439

以如下差異段來說:

@@ -4 +4,2 @@
-4444444444444444444
+4444444448878784444444444
+insert1

@@ 這一行,表示一個匯總信息,其中的-4,其實應該是-4,1。 “-“代表文件--- a/test.txt,4代表第四行,test.txt的第4行,就是4444444444444444444這一行,被省略的1,表示展示的text.txt從第4行開始的行的數量。

比如,4,2表示展示第4、5行,4,3表示展示第4、5、6行。

+4,2同理,”+”代表文件+++ a/test2.txt,也就是展示4開頭的兩行,即第4、5行。

大家再看看這個圖,不知道是不是可以理解了:

image-20220803105718439

另外,@@是header行,算是一個匯總信息,就像是一個協議包的包頭一樣,說明包的內容的長度等,或者像是http里的content-length字段。

接下來,就是具體的內容,

@@ -4 +4,2 @@
-4444444444444444444
+4444444448878784444444444
+insert1

比如,-4444444444444444444的「-」不僅表示屬於文件text.txt,還表示這行是要被刪除的。「+」也是同理,表示是要新增的行。

還有一種情況是,兩邊行相等(比如需要展示上下文的時候),這種時候的話,前綴就是一個空字符,「 」。

具體看下面:

//www.gnu.org/software/diffutils/manual/html_node/Detailed-Unified.html

image-20220803115758775

擴展資料:

//en.wikipedia.org/wiki/Diff#:~:text=The unified format (要會上網)

diff2html渲染unified format

之前提到unified format就是個中間格式,只要大家都按這個格式來,生態就建立起來了。

接下來,我們就把前面那個字符串用一個js庫:diff2html來渲染一下,看看效果。

先在js中定義個字面量diffString,再用diff2html這個js庫來渲染:

    const diffString = `--- a/test.txt
+++ b/test2.txt
@@ -4 +4,2 @@
-4444444444444444444
+4444444448878784444444444
+insert1
@@ -6 +7,3 @@
-666666666
\ No newline at end of file
+insert2
+666666666
+insert3`;


document.addEventListener('DOMContentLoaded', function () {
    const targetElement = document.getElementById('filesExistInBothDir');
    const configuration = {
        // 渲染文件列表
        drawFileList: true,
        // 文件列表顯示/隱藏的開關
        fileListToggle: false,
        // 默認展示文件列表
        fileListStartVisible: false,
        // 文件內容可收起/展開的開關
        fileContentToggle: true,
        matching: 'lines',
        // 左右兩側雙欄展示
        outputFormat: 'side-by-side',
        // 雙欄展示模式時,拖動左邊的橫向滾動條,右側同步滾動
        synchronisedScroll: true,
        // 高亮代碼
        highlight: true,
        renderNothingWhenEmpty: true,
    };
    const diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
    diff2htmlUi.draw();
    diff2htmlUi.highlightCode();

效果如下:

image-20220803131800285

html源文件上傳了,感興趣可以看看:

//dump-1252523945.cos.ap-shanghai.myqcloud.com/img/compare-result-162513.html