如果你曾有機(jī)會(huì)在一個(gè)使用分布式開(kāi)發(fā)模型的大型代碼庫(kù)上工作過(guò),你就應(yīng)該聽(tīng)說(shuō)過(guò)類(lèi)似下面的話,“Sue 剛發(fā)過(guò)來(lái)一個(gè)補(bǔ)丁patch”,“Rajiv 正在簽出checking out差異diff”, 可能這些詞(補(bǔ)丁、差異文件)對(duì)你而言很陌生,而你確定很想搞懂他們到底指什么。開(kāi)源軟件對(duì)上述提到的名詞有很大的貢獻(xiàn),作為大型項(xiàng)目從 Apache web 服務(wù)器到 Linux 內(nèi)核的開(kāi)發(fā)模型,“基于補(bǔ)丁文件的開(kāi)發(fā)” 這一模式貫穿了上述項(xiàng)目的始終。實(shí)際上,你可能不知道 Apache 的名字就來(lái)自“一系列的代碼補(bǔ)丁”(LCTT 譯注:Apache 英文發(fā)音和補(bǔ)丁的英文 patch 相似),它們被一一收集起來(lái)并針對(duì)原來(lái)的NCSA HTTPd server source code進(jìn)行了修訂。
你可能認(rèn)為這只不過(guò)是些逸聞,但是一份早期的Apache 網(wǎng)站的存檔中聲稱(chēng) Apache 的名字就是來(lái)自于最早的“補(bǔ)丁”集合;即“打了補(bǔ)丁的APAtCHy”服務(wù)器,簡(jiǎn)化為 Apache。
好了,言歸正傳,程序員嘴里說(shuō)的“差異”和“補(bǔ)丁”到底是什么?
首先,在這篇文章里,我們可以認(rèn)為這兩個(gè)術(shù)語(yǔ)都指向同一個(gè)概念。“diff” 是 ”difference“ 的簡(jiǎn)寫(xiě);Unix 下的同名工具程序diff剖析了一個(gè)或多個(gè)文件之間的“差異”。下面我們會(huì)看到diff的例子:
一個(gè)“補(bǔ)丁”指的是文件之間一系列差異,這些差異能被 Unix 的diff程序應(yīng)用在源代碼樹(shù)上。我們能使用diff工具來(lái)創(chuàng)建“差異”(或“補(bǔ)丁”),然后使用該工具將它們 “打” 在一個(gè)沒(méi)有這個(gè)補(bǔ)丁的同樣的源代碼版本上。此外,(我又要開(kāi)始跑題說(shuō)些歷史軼事了……),“補(bǔ)丁” 這個(gè)詞真的指在計(jì)算機(jī)的早期使用打卡機(jī)的時(shí)候,用來(lái)覆蓋在打孔紙帶上來(lái)對(duì)軟件進(jìn)行修改的覆蓋紙,那個(gè)時(shí)代打孔紙帶就是在計(jì)算機(jī)處理器上運(yùn)行的程序。下面來(lái)自維基頁(yè)面的這張圖真切的描繪了最初的“打補(bǔ)丁”這個(gè)詞的出處:
現(xiàn)在你對(duì)補(bǔ)丁和差異就了一個(gè)基本的概念,讓我們來(lái)看看軟件開(kāi)發(fā)者是怎么使用這些工具的。如果你還沒(méi)有使用過(guò)類(lèi)似于Git或subversion這樣的源代碼版本控制工具的話,我將會(huì)一步步展示最流行的軟件項(xiàng)目是怎么使用它們的。如果你將一個(gè)軟件的生命周期看成是一條時(shí)間線的話,你就能看見(jiàn)這個(gè)軟件的點(diǎn)滴變化,比如在何時(shí)源代碼加上了一個(gè)功能,在何時(shí)源代碼修復(fù)了一個(gè)功能缺陷。我們稱(chēng)這些改變的點(diǎn)為“提交commit”,“提交”這個(gè)詞被當(dāng)今最流行的源代碼版本管理工具 Git 所使用,當(dāng)你想檢查在一個(gè)提交前后的代碼變化的話,(或者在許多個(gè)提交之間的代碼變化),你都可以使用工具來(lái)觀察文件差異。
如果你同樣在使用 Git 開(kāi)發(fā)軟件的話,你可以在你的本地開(kāi)發(fā)環(huán)境做些希望交給別的開(kāi)發(fā)者的提交,以添加到他們的源代碼樹(shù)中。為了給別的開(kāi)發(fā)者你的提交,一個(gè)方法就是創(chuàng)建一個(gè)你本地文件的差異文件,然后將這個(gè)“補(bǔ)丁”發(fā)送給和你工作在同一個(gè)源代碼樹(shù)的別的開(kāi)發(fā)者。別的開(kāi)發(fā)者在“打”了你的補(bǔ)丁之后,就能看到在你的代碼變樹(shù)上的變化。
Linux、Git 和 GitHub
這種分享補(bǔ)丁的開(kāi)發(fā)模型正是現(xiàn)今 Linux 內(nèi)核社區(qū)如何處理內(nèi)核修改提議而采用的模型。如果你有機(jī)會(huì)瀏覽任何一個(gè)主流的 Linux 內(nèi)核郵件列表 —— 主要是LKML,也包括linux-containers、fs-devel、Netdev等等,你能看到很多開(kāi)發(fā)者會(huì)貼出他們想讓其他內(nèi)核開(kāi)發(fā)者審核、測(cè)試或者合入 Linux 官方 Git 代碼樹(shù)某個(gè)位置的補(bǔ)丁。當(dāng)然,討論 Git 不在這篇文章范圍之內(nèi)(Git 是由 Linus Torvalds 開(kāi)發(fā)的源代碼控制系統(tǒng),它支持分布式開(kāi)發(fā)模型以及允許獨(dú)立于主要代碼倉(cāng)庫(kù)的補(bǔ)丁包,這些補(bǔ)丁包能被推送或拉取到不同的源代碼樹(shù)上,并遵守這些代碼樹(shù)各自的開(kāi)發(fā)流程。)
在繼續(xù)我們的話題之前,我們當(dāng)然不能忽略和補(bǔ)丁和差異這個(gè)概念相關(guān)的最流行的服務(wù):GitHub。從它的名字就能猜想出 GitHub 是基于 Git 的,而且它還圍繞著 Git 對(duì)分布式開(kāi)源代碼開(kāi)發(fā)模型提供了基于 Web 和 API 的工作流管理。(LCTT 譯注:即拉取請(qǐng)求Pull Request)。在 GitHub 上,分享補(bǔ)丁的方式不是像 Linux 內(nèi)核社區(qū)那樣通過(guò)郵件列表,而是通過(guò)創(chuàng)建一個(gè)拉取請(qǐng)求。當(dāng)你提交你自己的源代碼樹(shù)的改動(dòng)時(shí),你能通過(guò)創(chuàng)建一個(gè)針對(duì)軟件項(xiàng)目的共享倉(cāng)庫(kù)的“拉取請(qǐng)求”來(lái)分享你的代碼改動(dòng)(LCTT 譯注:即核心開(kāi)發(fā)者維護(hù)一個(gè)主倉(cāng)庫(kù),開(kāi)發(fā)者去“復(fù)刻fork”這個(gè)倉(cāng)庫(kù),待各自的提交后再創(chuàng)建針對(duì)這個(gè)主倉(cāng)庫(kù)的拉取請(qǐng)求,所有的拉取請(qǐng)求由主倉(cāng)庫(kù)的核心開(kāi)發(fā)者批準(zhǔn)后才能合入主代碼庫(kù)。)GitHub 被當(dāng)今很多活躍的開(kāi)源社區(qū)所采用,如Kubernetes、Docker、容器網(wǎng)絡(luò)接口 (CNI)、Istio等等。在 GitHub 的世界里,用戶會(huì)傾向于使用基于 Web 頁(yè)面的方式來(lái)審核一個(gè)拉取請(qǐng)求里的補(bǔ)丁或差異,你也可以直接訪問(wèn)原始的補(bǔ)丁并在命令行上直接使用它們。
該說(shuō)點(diǎn)干貨了
我們前面已經(jīng)講了在流行的開(kāi)源社區(qū)里是怎么應(yīng)用補(bǔ)丁和差異的,現(xiàn)在看看一些例子。
第一個(gè)例子包括一個(gè)源代碼樹(shù)的兩個(gè)不同副本,其中一個(gè)有代碼改動(dòng),我們想用diff來(lái)看看這些改動(dòng)是什么。這個(gè)例子里,我們想看的是“合并格式unified”的補(bǔ)丁,這是現(xiàn)在軟件開(kāi)發(fā)世界里最通用的格式。如果想知道更詳細(xì)參數(shù)的用法以及如何生成差異文件,請(qǐng)參考diff手冊(cè)。原始的代碼在sources-orig目錄,而改動(dòng)后的代碼在sources-fixed目錄。如果要在你的命令行上用“合并格式”來(lái)展示補(bǔ)丁,請(qǐng)運(yùn)行如下命令。(LCTT 譯注:參數(shù)-N代表如果比較的文件不存在,則認(rèn)為是個(gè)空文件,-a代表將所有文件都作為文本文件對(duì)待,-u代表使用合并格式并輸出上下文,-r代表遞歸比較目錄)
$ diff -Naur sources-orig/ sources-fixed/
……下面是 diff 命令的輸出:
最開(kāi)始幾行 diff 命令的輸出可以這樣解釋?zhuān)喝齻€(gè) --- 顯示了原來(lái)文件的名字;任何在原文件(LCTT 譯注:不是源文件)里存在而在新文件里不存在的行將會(huì)用前綴 -,用來(lái)表示這些行被從源代碼里“減去”了。而 +++ 表示的則相反:在新文件里被加上的行會(huì)被放上前綴 +,表示這是在新文件里被“加上”的行。補(bǔ)丁文件中的每一個(gè)補(bǔ)丁“塊”(用 @@ 作為前綴的的部分)都有上下文的行號(hào),這能幫助補(bǔ)丁工具(或其它處理器)知道在代碼的哪里應(yīng)用這個(gè)補(bǔ)丁塊。你能看到我們已經(jīng)修改了“Office Space”這部電影里提到的那個(gè)函數(shù)(移除了三行并加上了一行代碼注釋?zhuān)娪袄锬莻€(gè)有點(diǎn)貪心的工程師可是偷偷的在計(jì)算利息的函數(shù)里加了點(diǎn)“料”哦。(LCTT譯注:劇情詳情請(qǐng)見(jiàn)電影 https://movie.douban.com/subject/1296424/)
如果你想找人來(lái)測(cè)試你的代碼改動(dòng),你可以將差異保存到一個(gè)補(bǔ)丁里:
$ diff -Naur sources-orig/ sources-fixed/ >myfixes.patch
現(xiàn)在你有補(bǔ)丁 myfixes.patch 了,你能把它分享給別的開(kāi)發(fā)者,他們可以將這個(gè)補(bǔ)丁打在他們自己的源代碼樹(shù)上從而得到和你一樣的代碼并測(cè)試他們。如果一個(gè)開(kāi)發(fā)者的當(dāng)前工作目錄就是他的源代碼樹(shù)的根的話,他可以用下面的命令來(lái)打補(bǔ)?。?/p>
$patch -p1 < ../myfixes.patch
patching file officespace/interest.go
現(xiàn)在這個(gè)開(kāi)發(fā)者的源代碼樹(shù)已經(jīng)打好補(bǔ)丁并準(zhǔn)備好構(gòu)建和測(cè)試文件的修改了。那么如果這個(gè)開(kāi)發(fā)者在打補(bǔ)丁之前已經(jīng)改動(dòng)過(guò)了怎么辦?只要這些改動(dòng)沒(méi)有直接沖突(LCTT 譯注:比如改在同一行上),補(bǔ)丁工具就能自動(dòng)的合并代碼的改動(dòng)。例如下面的interest.go 文件,它有其它幾處改動(dòng),然后它想打上 myfixes.patch 這個(gè)補(bǔ)?。?/p>
$patch -p1 < ../myfixes.patch
patching file officespace/interest.go
Hunk#1 succeeded at 26 (offset 15 lines).
在這個(gè)例子中,補(bǔ)丁警告說(shuō)代碼改動(dòng)并不在文件原來(lái)的地方而是偏移了 15 行。如果你文件改動(dòng)的很厲害,補(bǔ)丁可能干脆說(shuō)找不到要應(yīng)用的地方,還好補(bǔ)丁程序提供了提供了打開(kāi)“模糊”匹配的選項(xiàng)(這個(gè)選項(xiàng)在文檔里有預(yù)置的警告信息,對(duì)其講解已經(jīng)超出了本文的范圍)。
如果你使用 Git 或者 GitHub 的話,你可能不會(huì)直接使用補(bǔ)丁或差異。Git 已經(jīng)內(nèi)置了這些功能,你能使用這些功能和共享一個(gè)源代碼樹(shù)的其他開(kāi)發(fā)者交互,拉取或合并代碼。Git 一個(gè)比較相近的功能是可以使用 git diff 來(lái)對(duì)你的本地代碼樹(shù)生成全局差異,又或者對(duì)你的任意兩次”引用“(可能是一個(gè)代表提交的數(shù)字,或一個(gè)標(biāo)記或分支的名字,等等)做全局補(bǔ)丁。你甚至能簡(jiǎn)單的用管道將 git diff 的輸出到一個(gè)文件里(這個(gè)文件必須嚴(yán)格符合將要被使用它的程序的輸入要求),然后將這個(gè)文件交給一個(gè)并不使用 Git 的開(kāi)發(fā)者應(yīng)用到他的代碼上。當(dāng)然,GitHub 把這些功能放到了 Web 上,你能直接在 Web 頁(yè)面上查看一個(gè)拉取請(qǐng)求的文件變動(dòng)。在 Web 上你能看到所展示的合并差異,GitHub 還允許你將這些代碼改動(dòng)下載為原始的補(bǔ)丁文件。
總結(jié)
好了,你已經(jīng)學(xué)到了”差異“和”補(bǔ)丁“是什么,以及在 Unix/Linux 上怎么使用命令行工具和它們交互。除非你還在像 Linux 內(nèi)核開(kāi)發(fā)這樣的項(xiàng)目中工作而使用完全基于補(bǔ)丁文件的開(kāi)發(fā)方式,你應(yīng)該會(huì)主要通過(guò)你的源代碼控制系統(tǒng)(如 Git)來(lái)使用補(bǔ)丁。但熟悉像 GitHub 這樣的高級(jí)別工具的技術(shù)背景和技術(shù)底層對(duì)你的工作也是大有裨益的。誰(shuí)知道會(huì)不會(huì)有一天你需要和一個(gè)來(lái)自 Linux 世界郵件列表的補(bǔ)丁包打交道呢?
-
Linux
+關(guān)注
關(guān)注
87文章
11378瀏覽量
211341 -
服務(wù)器
+關(guān)注
關(guān)注
12文章
9432瀏覽量
86506 -
源代碼
+關(guān)注
關(guān)注
96文章
2948瀏覽量
67206
原文標(biāo)題:差異文件(diff)和補(bǔ)丁文件(patch)簡(jiǎn)介
文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
在STM32實(shí)現(xiàn)命令行
Linux命令行工具
用命令行管理IIS的FTP站點(diǎn)
Xilinx軟件命令行工具:XSCT開(kāi)發(fā)和調(diào)試
Xilinx軟件命令行工具進(jìn)行開(kāi)發(fā)和調(diào)試
維基鏈的命令行是如何高效快速的對(duì)維基鏈節(jié)點(diǎn)進(jìn)行操作的
Golang基于flag庫(kù)實(shí)現(xiàn)一個(gè)命令行工具
如何使用命令行在Linux中查找文件?
通用命令行工具ADB(Android Debug Bridge)常見(jiàn)的ADB命令
pycharm命令行終端運(yùn)行代碼
eclipse怎么使用命令行
HarmonyOS開(kāi)發(fā):【基于命令行(安裝庫(kù)和工具集)】

評(píng)論