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。

    1.git diff生成的标准patch

    我们可以首先用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'

    我们现在有一个patch文件,并且签出了master,接下来我们可以使用git apply来应用这个patch。当然了,实际应用中,我们不会这样在一个分支建patch,到另一个分支去应用,因为只有merge一下就好了。我们现 在权当没有这个Fix分支。一般情况下,为了保护master,我们会建立一个专门处理新交来的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。

    2.git format-patch生成的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的文件,你可以直接发送它!这种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!!!

    不过要注意的是,如果master与Fix分支中间有多次提交,它会针对每次提交生成一个patch。

    3.两种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生成补丁。
     
     
     
     
     
    以下转自:http://blog.csdn.net/daydring/article/details/42676987
     
    1 使用git format-patch生成所需要的patch:
    当前分支所有超前master的提交:
    git format-patch -M master
    某次提交以后的所有patch:
    git format-patch 4e16 --4e16指的是commit名
    从根到指定提交的所有patch:
    git format-patch --root 4e16
    某两次提交之间的所有patch:
    git format-patch 365a..4e16 --365a和4e16分别对应两次提交的名称
    某次提交(含)之前的几次提交:
    git format-patch –n 07fe --n指patch数,07fe对应提交的名称
    故,单次提交即为:
    git format-patch -1 07fe
    git format-patch生成的补丁文件默认从1开始顺序编号,并使用对应提交信息中的第一行作为文件名。如果使用了-- numbered-files选项,则文件名只有编号,不包含提交信息;如果指定了--stdout选项,可指定输出位置,如当所有patch输出到一个文件;可指定-o <dir>指定patch的存放目录;


    2应用patch:
    先检查patch文件:git apply --stat newpatch.patch
    检查能否应用成功:git apply --check newpatch.patch
    打补丁:git am --signoff < newpatch.patch

    (使用-s或--signoff选项,可以commit信息中加入Signed-off-by信息)

    如果应用patch出现问题:

    比如,一个典型的git am失败,可能是这样的:
    $ git am PATCH
    Applying: PACTH DESCRIPTION
    error: patch failed: file.c:137
    error: file.c: patch does not apply
    error: patch failed: Makefile:24
    error: libavfilter/Makefile: patch does not apply
    Patch failed at 0001 PATCH DESCRIPTION
    When you have resolved this problem run "git am --resolved".
    If you would prefer to skip this patch, instead run "git am --skip".
    To restore the original branch and stop patching run "git am --abort".
     
    正如你所见,如果冲突发生,git只是输出上述信息,然后就停下来。一个小冲突会导致整个patch都不会被集成。
     
    处理这种问题的最简单方法是先使用 git am --abort,然后手动的添加此patch, patch -p1 < PATCH,手动解决掉代码冲突,最后使用 git commit -a 提交代码。但是这样做有个问题就是你会失去PATCH中原本包含的commit信息(比如From,Date,Subject,Signed-off-by等)。应该有一种更聪明的方法。
     
    在 .git/rebase-apply 目录下,存放着相应的补丁文件,名字是“0001” (在更新的git版本中,存放补丁文件的目录名有所改变,这里使用的git版本是 1.7.4.1)。
     
    事实上,你可以使用 git apply 命令打patch(git apply 是git中的patch命令)。如同使用 patch -p1 命令时一样,然后手动解决代码冲突(检视生成的 .rej 文件,与冲突文件比较,修改冲突内容,并最终把文件加入到index中):
     
    $ git apply PATCH --reject
    $ edit edit edit
    (译注:根据.rej文件手动解决所有冲突)
    $ git add FIXED_FILES
    $ git am --resolved
     
    就这么简单!
    想多一些解释,好吧。git am 并不改变index,你需要使用 git apply --reject 打patch(保存在 .git/rebase-apply),手动解决代码冲突,(译注:使用 git status 列出所有涉及文件),把所有文件(不仅仅是引起冲突的文件)添加到(git add)index,最后告诉 git am 你已经解决(--resolved)了问题。这样做的好处是你不需要重新编辑commit信息。而且,如果你正在打的是一系列patch(就是说你在打的是多个patch,比如 git am *.patch)你不需要使用 git am --abort,然后又 git am。

    参考资料:

    Git-format-patch(1) - Linux man page http://linux.die.net/man/1/git-format-patch

    How to create and apply a patch with Git http://ariejan.net/2009/10/26/how-to-create-and-apply-a-patch-with-git

     
  • 相关阅读:
    Domain Logic approaches
    Load data local infile 实验报告
    eclipse导入Maven项目
    MYSQL数据库导入数据时出现乱码的解决办法
    mysql创建用户并分配权限
    CDI Features
    Java Design Patterr
    关联tomcat源代码
    Spring AOP Capabilities and Goals
    CDI FEATURES
  • 原文地址:https://www.cnblogs.com/dirt2/p/5553165.html
Copyright © 2011-2022 走看看