Git的Patch功能

http://www.cnblogs.com/y041039/articles/2411600.html
一、前言
UNIX世界的軟件開發大多都是協作式的,因此,Patch(補丁)是一個相當重要的東西,因爲幾乎所有的大型UNIX項目的普通貢獻者,都是通過Patch來提交代碼的。作爲最重要的開源項目之一,Linux,也是這樣的。普通開發者從軟件倉庫clone下代碼,然後寫入代碼,做一個Patch, 最後用E-mail發給Linux Kernel的維護者就好了。Git最初作爲Linux的版本控制工具,提供了透明、完整、穩定的Patch功能
   我們先介紹一下Patch是什麼。如果一個軟件有了新版本,我們可以完整地下載新版本的代碼進行編譯安裝。然而,像Linux Kernel這樣的大型項目,代碼即使壓縮,也超過70MB,每次全新下載是有相當大的代價的。然而,每次更新變動的代碼可能不超過1MB,因此,我們只 要能夠有兩個版本代碼的diff的數據,應該就可以以極低的代價更新程序了。因此,Larry Wall開發了一個工具:patch。它可以根據一個diff文件進行版本更新。
  不過在git中,我們沒有必要直接使用diff和patch來做補丁,這樣做既危險又麻煩。
git提供了兩種簡單的patch方案。一是用git diff生成的標準patch,二是git format-patch生成的Git專用Patch
二、git diff生成的標準patch
2.1、製作標準補丁
我們可以首先用git diff製作一個patch
本文示例的工作目錄裏最初有一個文件a,內容是“This is the file a.”,放置在master分支中。爲了修改代碼,我們一般的做法是建立一個新分支:
sweetdum@sweetdum-ASUS:~/GitEx$ git branch Fix
sweetdum@sweetdum-ASUS:~/GitEx$ git checkout Fix
Switched to branch 'Fix'
接下來我們在a文件裏面追加一行,然後執行git diff
sweetdum@sweetdum-ASUS:~/GitEx$ echo 'Fix!!!'>>a
sweetdum@sweetdum-ASUS:~/GitEx$ git diff
diff --git a/a b/a
index 4add65f..0d295ac 100644
--- a/a
+++ b/a
@@ -1 +1,2 @@
This is the file a.
+Fix!!!
我們看到了Git diff的輸出,這是一個非常典型的Patch式diff。這樣我們可以直接把這個輸出變爲一個Patch:
sweetdum@sweetdum-ASUS:~/GitEx$ git commit -a -m "Fix"
[Fix b88c46b] Fix
1 files changed, 1 insertions(+), 0 deletions(-)
sweetdum@sweetdum-ASUS:~/GitEx$ git diff master > patch
sweetdum@sweetdum-ASUS:~/GitEx$ git checkout master
Switched to branch 'master'
2.2、應用標準補丁
我們現在有一個patch文件,並且簽出了master,接下來我們可以使用git apply來應用這個patch。當然了,實際應用中,我們不會這樣在一個分支建patch,到另一個分支去應用,因爲只有merge一下就好了。我們現 在權當沒有這個Fix分支。一般情況下,爲了保護master,我們會建立一個名叫PATCH的分支來專門處理新提交來的patch的
sweetdum@sweetdum-ASUS:~/GitEx$ git branch PATCH
sweetdum@sweetdum-ASUS:~/GitEx$ git checkout PATCH
Switched to branch 'PATCH'
sweetdum@sweetdum-ASUS:~/GitEx$ git apply patch
sweetdum@sweetdum-ASUS:~/GitEx$ git commit -a -m "Patch Apply"
[PATCH 9740af8] Patch Apply
1 files changed, 1 insertions(+), 0 deletions(-)
看,現在我們在PATCH分支中應用了這個補丁,我們可以把PATCH分支和Fix比對一下,結果肯定是什麼也沒有,說明PATCH分支和Fix分支完全一樣。patch應用成功。即使有多個文件git diff 也能生成一個patch。
三、git format-patch生成的git專用補丁
3.1、製作git專用補丁
我們同樣用上面那個例子的工作目錄,這次,我們在Fix分支中的a添加了新行之後,用git format-patch生成一個patch。
sweetdum@sweetdum-ASUS:~/GitEx$ git checkout Fix
Switched to branch 'Fix'
sweetdum@sweetdum-ASUS:~/GitEx$ echo 'Fix!!!'>>a
sweetdum@sweetdum-ASUS:~/GitEx$ git commit -a -m "Fix1"
[Fix 6991743] Fix1
1 files changed, 1 insertions(+), 0 deletions(-)
sweetdum@sweetdum-ASUS:~/GitEx$ git format-patch -M master
0001-Fix1.patch
git format-patch的-M選項表示這個patch所在的當前分支要和那個分支比對。現在它生成了一個patch文件,我們看看那是什麼:
sweetdum@sweetdum-ASUS:~/GitEx$ cat 0001-Fix1.patch
From 6991743354857c9a6909a253e859e886165b0d90 Mon Sep 17 00:00:00 2001
From: Sweetdumplings <[email protected]>
Date: Mon, 29 Aug 2011 14:06:12 +0800
Subject: [PATCH] Fix1
---
a |    1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/a b/a
index 4add65f..0d295ac 100644
--- a/a
+++ b/a
@@ -1 +1,2 @@
This is the file a.
+Fix!!!
--
1.7.4.1
看,這次多了好多東西,不僅有diff的信息,還有提交者,時間等等,仔細一看你會發現,這是個E-mail的文件,你可以直接發送它!
注意如果master與Fix分支中間有多次提交,它會針對每次提交生成一個patch
3.2、應用git專用補丁
git format-patch生成的補丁,必須使git am命令來應用。
sweetdum@sweetdum-ASUS:~/GitEx$ git checkout master
Switched to branch 'master'
sweetdum@sweetdum-ASUS:~/GitEx$ git branch PATCH
sweetdum@sweetdum-ASUS:~/GitEx$ git checkout PATCH
sweetdum@sweetdum-ASUS:~/GitEx$ git am 0001-Fix1.patch
Applying: Fix1
sweetdum@sweetdum-ASUS:~/GitEx$ git commit -a -m "PATCH apply"
在提交了補丁之後,我們可以再看看目前文件a的情況:
sweetdum@sweetdum-ASUS:~/GitEx$ cat a
This is the file a.
Fix!!!
果然,多了一個Fix!!!
3.3、應用多個git專用patch
因爲在git使用當中,會有很多時候別人(供應商或者其他的開發人員)發過來一系列的patch,這些patch通常的是類似這樣的名字:
git-am 可以一次合併一個文件,或者一個目錄下所有的patch,或者你的郵箱目錄下的patch.
在使用git-am之前, 你要首先git am –abort 一次,來放棄掉以前的am信息,這樣纔可以進行一次全新的am。
不然會遇到這樣的錯誤。
.git/rebase-apply still exists but mbox given.
下面舉兩個例子:
示例1
你現在有一個code base: small-src, 你的patch文件放在~/patch/0001-trival-patch.patch
cd small-src
git am ~/patch/0001-trival-patch.patch
如果成功patch上去, 你就可以去喝杯茶了。
如果失敗了, git 會提示錯誤, 比如:
error: patch failed: android/mediascanner.cpp:452
error: android/mediascanner.cpp: patch does not apply
這樣你就需要先看看patch, 然後改改錯誤的這個文件,讓這個patch能夠patch上去。
示例2
你有一堆patch, 名字是上面提到的那一堆patch, 你把他們放在~/patch-set/目錄下(路徑隨意)
cd opencore
git am ~/patch-set/*.patch
(這裏git就會按照文件名的順序一次am這些patch)
如果一切順利, 你所有的patch都OK了, 你又Lucky了。
3.4、應用git專用補丁失敗
在使用git am打補丁時,如果中間遇到了應用某個patch失敗,那麼git am就會停到打這個patch的地方, 告訴你是哪個patch打不上去。
比如我現在有一個文件file,有兩個patch.
file 的內容是
the text

more text
兩個patch分別是:
0001-add-line.patch補丁文件:
From 48869ccbced494e05738090afa5a54f2a261df0f Mon Sep 17 00:00:00 2001
From: zhangjiejing <zhangjiejing@zhangjiejing-desktop.(none)>
Date: Thu, 22 Apr 2010 13:04:34 +0800
Subject: [PATCH 1/2] add line

---
 file |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/file b/file
index 067780e..685f0fa 100644
--- a/file
+++ b/file
@@ -3,3 +3,5 @@ file:
 some text

 more text
+
+add line
--
1.6.3.3
0002-change-line.patch補丁文件:
From f756e1b3a87c216b7e0afea9d15badd033171578 Mon Sep 17 00:00:00 2001
From: zhangjiejing <zhangjiejing@zhangjiejing-desktop.(none)>
Date: Thu, 22 Apr 2010 13:05:19 +0800
Subject: [PATCH 2/2] change line

---
 file |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/file b/file
index 685f0fa..7af7852 100644
--- a/file
+++ b/file
@@ -1,6 +1,6 @@
 file:

-some text
+Change line text

 more text

--
1.6.3.3
運行
git am *.patch來應用這些patch, 報錯, Patch failed at 0001 add line
這樣我們看0001這個patch,原來patch需要的是some text, 而file裏面是the text, 所以我們用編輯器把這行改成some text,
vi file
git apply 0001-add-line.patch
git add file
git am --resolved
在解決完衝突以後, 比如用git add來讓git知道你已經解決完衝突了。
如果你發現這個衝突是無法解決的, 要撤銷整個am的東西。 可以運行git am –abort
如果你想只是忽略這一個patch,可以運行git am –skip來跳過這個patch.
四、兩種patch的比較
兼容性:很明顯,git diff生成的Patch兼容性強。如果你在修改的代碼的官方版本庫不是Git管理的版本庫,那麼你必須使用git diff生成的patch才能讓你的代碼被項目的維護人接受。
除錯功能:對於git diff生成的patch,你可以用git apply --check 查看補丁是否能夠乾淨順利地應用到當前分支中;如果git format-patch 生成的補丁不能打到當前分支,git am會給出提示,並協助你完成打補丁工作,你也可以使用git am -3進行三方合併,詳細的做法可以參考git手冊或者《Progit》。從這一點上看,兩者除錯功能都很強。
版本庫信息:由於git format-patch生成的補丁中含有這個補丁開發者的名字,因此在應用補丁時,這個名字會被記錄進版本庫,顯然,這樣做是恰當的。因此,目前使用Git的開源社區往往建議大家使用format-patch生成補丁。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章