zoukankan      html  css  js  c++  java
  • 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 <linmx0130@163.com>
    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生成补丁。
  • 相关阅读:
    修复 Visual Studio Error “No exports were found that match the constraint”
    RabbitMQ Config
    Entity Framework Extended Library
    Navisworks API 简单二次开发 (自定义工具条)
    NavisWorks Api 简单使用与Gantt
    SQL SERVER 竖表变成横表
    SQL SERVER 多数据导入
    Devexpress GridControl.Export
    mongo DB for C#
    Devexress XPO xpPageSelector 使用
  • 原文地址:https://www.cnblogs.com/xingzc/p/5987043.html
Copyright © 2011-2022 走看看