如何提取统一差异(unified-diff)风格的补丁子集?

3
每次我想要提取一个补丁的子集,我都需要编写脚本来仅提取我想要的索引。 例如,我有一个适用于子目录“yay”和“foo”的补丁。 有没有一种方法可以创建一个新的补丁或仅应用补丁的子集?即从现有补丁中创建一个只获取所有位于子目录“yay”下的索引或所有不位于子目录“foo”下的索引的新补丁。 如果我有像下面这样的补丁(请原谅以下伪补丁):
Index : foo/bar
 yada
 yada
- asdf
+ jkl
 yada
 yada
Index : foo/bah
 blah
 blah
- 28
+ 29
 blah
 blah
 blah
Index : yay/team
 go
 huskies
- happy happy
+ joy joy
 cougars
 suck

我该如何提取或应用只有'yay'子目录?例如:

Index : yay/team
 go
 huskies
- happy happy
+ joy joy
 cougars
 suck

我知道如果我编写一个解决方案,就会重复造轮子。
3个回答

3

请查看patchutils工具集中的filterdiff实用程序。

例如,如果您有以下补丁:

$ cat example.patch
diff -Naur orig/a/bar new/a/bar
--- orig/a/bar  2009-12-02 12:41:38.353745751 -0800
+++ new/a/bar   2009-12-02 12:42:17.845745951 -0800
@@ -1,3 +1,3 @@
 4
-5
+e
 6
diff -Naur orig/a/foo new/a/foo
--- orig/a/foo  2009-12-02 12:41:32.845745768 -0800
+++ new/a/foo   2009-12-02 12:42:25.697995617 -0800
@@ -1,3 +1,3 @@
 1
 2
-3
+c
diff -Naur orig/b/baz new/b/baz
--- orig/b/baz  2009-12-02 12:41:42.993745756 -0800
+++ new/b/baz   2009-12-02 12:42:37.585745735 -0800
@@ -1,3 +1,3 @@
-7
+z
 8
 9

接下来,您可以运行以下命令来提取仅位于a目录中的补丁,如下所示:

$ cat example.patch | filterdiff -i 'new/a/*'
--- orig/a/bar  2009-12-02 12:41:38.353745751 -0800
+++ new/a/bar   2009-12-02 12:42:17.845745951 -0800
@@ -1,3 +1,3 @@
 4
-5
+e
 6
--- orig/a/foo  2009-12-02 12:41:32.845745768 -0800
+++ new/a/foo   2009-12-02 12:42:25.697995617 -0800
@@ -1,3 +1,3 @@
 1
 2
-3
+c

1
作为对sigjuice在评论中的请求的回应,我将发布我的脚本解决方案。它并不是100%防弹的,我可能会改用filterdiff。
base_usage_str=r'''
    python %prog index_regex patch_file

description:
    Extracts all indices from a patch-file matching 'index_regex'

    e.g.
        python %prog '^evc_lib' p.patch > evc_lib_p.patch

        Will extract all indices which begin with evc_lib.

        -or-

        python %prog '^(?!evc_lib)' p.patch > not_evc_lib_p.patch

        Will extract all indices which do *not* begin with evc_lib.

authors:
    Ross Rogers, 2009.04.02
'''

import re,os,sys
from optparse import OptionParser

def main():

    parser = OptionParser(usage=base_usage_str)

    (options, args) = parser.parse_args(args=sys.argv[1:])

    if len(args) != 2:
        parser.print_help()
        if len(args) == 0:
            sys.exit(0)
        else:
            sys.exit(1)

    (index_regex,patch_file) = args
    sys.stderr.write('Extracting patches for indices found by regex:%s\n'%index_regex)
    #print 'user_regex',index_regex
    user_index_match_regex = re.compile(index_regex)

    # Index: verification/ring_td_cte/tests/mmio_wr_td_target.e
    # --- sw/cfg/foo.xml      2009-04-30 17:59:11 -07:00
    # +++ sw/cfg/foo.xml      2009-05-11 09:26:58 -07:00

    index_cre = re.compile(r'''(?:(?<=^)|(?<=\n))(--- (?:.*\n){2,}?(?![ @\+\-]))''')

    patch_file = open(patch_file,'r')
    all_patch_sets = index_cre.findall(patch_file.read())
    patch_file.close()

    for file_edit in all_patch_sets:
        # extract index subset
        index_path = re.compile('\+\+\+ (?P<index>[\w_\-/\.]+)').search(file_edit).group('index').strip()
        if user_index_match_regex.search(index_path):
            sys.stderr.write("Index regex matched index: "+index_path+"\n")
            print file_edit,


if __name__ == '__main__':
    main()

1
这是我的Perl快速而简单的解决方案。
perl -ne '@a = split /^Index :/m, join "", <>; END { for(@a) {print "Index :", $_ if (m, yay/team,)}}' < foo.patch

:-) 嗯,我以前做过几个类似的...我希望一些Unix大师能告诉我“哦,是那个blah命令”。 - Ross Rogers
把这个转化为通用工具应该不难。例如,“patch-grep regex”,其中regex被应用于补丁中的文件名。 - sigjuice
你说得对。我已经按照你的建议去做了。只不过是用 Python(让圣战开始吧!) - Ross Rogers
你介意在这里分享一下你的Python版本吗?我是个Python新手,我会非常感兴趣。 - sigjuice
嘿,sigjuice,我没看到你的评论。我发布了我的代码,但已经晚了半年。 - Ross Rogers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接