使用python unidiff库分析git diff

背景

这里分享一个python写的分离特定的git修改的方法。
主要应用的问题是当时项目组需要同步chromium最新代码,结果带来了巨大量的改动,为了节省我们review新代码的时间,需要将一些不重要的修改(携带某种特征,例如新版本的chromium大量替换了智能指针,将自研的scoped_ptr变成了std::unique_ptr)分离出来,剩下的就是重要的修改了。

解决方案

这里主要用到python的unidiff库,这个库可以解析出标准的unified diff data,git diff恰好就是这个格式。
这个库能精确的最小维度叫做hunk。
所谓hunk,可以理解为diff中的
@@ -162,8 +162,8 @@
xxx代码

这样一块东西,这通常是某个file中的一段连续的修改,而且可以抽离出来单独进行git apply(打代码补丁)

样例代码

该脚本可以利用PatchSet hunk特性,对hunk中的关键语句、字词进行过滤,实现抓取 or 去掉该hunk的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#coding=utf-8
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import os
import sys
reload (sys)
sys.setdefaultencoding('utf-8')
import string
from unidiff import PatchSet
def main():
filename = sys.argv[1]
try:
patch = PatchSet.from_filename(filename, encoding='utf-8') #获取git diff
except Exception as e:
print str(e)
return
for f in patch:
if f.path.split('.')[-1] not in ('cc', 'h', 'cpp', 'c', 'mm'):
continue
source = "--- %s" % f.source_file
target = "+++ %s" % f.target_file
for hunk in f:
is_hint = True
for line in hunk:
strline = str(line)
#对关键词进行过滤
if line.is_context or '#include' in strline or '#define' in strline or '//' in strline:
continue
if 'scoped_ptr' in strline or 'unique_ptr' in strline or 'make_scoped_ptr' in strline or 'WrapUnique' in strline:
continue
is_hint = False
if is_hint:
#满足我需要的条件,则进行输出,这里只是进行简单的print,也可输出到file,然后 git apply file即可对使用这些抽离出来的代码对库做补丁
print source
print target
print hunk
if __name__ == '__main__':
main()