安卓sdk项目小的几十G,大的上百G,有的人会把sdk分成许多个小的git然后统一用repo来管理,还有的人会选择把sdk放在一个git中管理. 那么repo中修改后生成的patch是无法直接给git用的,因为路径不一样,patch内容也不相符
比如repo中device子目录是一个git,那么它生成的patch放到另一个git项目中只能cd到device路径,然后再用patch指令打,无法用git am xx.patch来打. 两边同步代码会很麻烦.
需要用脚本进行一个转换.
repo生成manifest快照
repo比如要生成0801到0805之间的修改的patch
8月1号用如下指令生成快照
./repo sync
./repo manifest -r -o manifest_0801.xml
中间做过修改.
8月5号再生成快照
./repo sync
./repo manifest -r -o manifest_0805.xml
得有两个快照, 才能生成这两个快照之间的diff提交.
生成快照后,接下来用脚本来生成两个快照间的修改的patch
生成repo快照间的提交的patch并转换成git am的patch
# 作者帅得不敢出门
# -*- coding: utf-8 -*-
import sys
import os
import re
import subprocess
def do_popen(cmd):
#popen
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=True)
stdout, stderr = process.communicate()
return stdout.decode('utf-8')
def auto_detect_manifests():
"""遍历repo项目根目录,找到两个快照,快照以.xml结尾"""
manifests = []
for item in os.listdir('./'):
if item.startswith('manifest') and item.endswith('.xml'):
manifests.append(item)
if len(manifests) != 2:
print('Error:the number of manifest_xx.xml files are not equal to 2, abort!')
sys.exit(1)
manifests.sort()
print(manifests)
return manifests
def get_diffmanifests():
"""
查看两个repo快照间的差异, 得到类似如下
changed projects :
bootable/bootloader/lk changed from e5f360f35a6d3848475ba4920f40c1609b1348b0 to ca0100b2da6ca7831348cb5fcfe8d23c529e8a57
[+] ca0100b2 edit 1
device/sprd/sepolicy changed from f15d0189283f767bd315f0900a59256323c071c2 to 64c586a362cb19a290280e79b2e20e8aab7d94cc
[+] 64c586a hello
kernel/msm-3.18 changed from f36f37a42a94fe78d5d7cbe2e8a4ab6477de74ab to 6b372c76fc0874d19822d978ad557a4aeec0ebee
[+] 6b372c76fc08 word
"""
manifests = auto_detect_manifests()
cmd = './repo diffmanifests ' + manifests[0] + ' ' + manifests[1]
print(cmd)
return do_popen(cmd)
def get_diff_git_log():
"""
得到两个repo快照间的git修改的log
[{'path': 'bootable/bootloader/lk', 'from': 'e5f360f35a6d3848475ba4920f40c1609b1348b0', 'to': 'ca0100b2da6ca7831348cb5fcfe8d23c529e8a57'}, {'path': 'device/sprd/sepolicy', 'from': 'f15d0189283f767bd315f0900a59256323c071c2', 'to': '64c586a362cb19a290280e79b2e20e8aab7d94cc'}, {'path': 'kernel/msm-3.18', 'from': 'f36f37a42a94fe78d5d7cbe2e8a4ab6477de74ab', 'to': '6b372c76fc0874d19822d978ad557a4aeec0ebee'}]
"""
data = get_diffmanifests()
print(data)
# 只保留\t开头的有效行
line = [ x for x in data.split('\n') if x.startswith('\t')]
ret = []
for i in range(len(line)):
if i % 2 == 0:
#print(line[i])
log = line[i].split()
ret.append({'path':log[0], 'from':log[3], 'to':log[5]})
#print(ret)
return ret
def get_format_patch(log, outdir):
try:
do_popen('rm ./*.patch ')
except Exception as e:
print('')
# 生成从from开始的提交的git patch,生成的git是在子目录中生成的,所以需要在patch内容中的文件路径添加父目录
do_popen('git format-patch ' + log['from'])
for file in os.listdir('./'):
if file.endswith('.patch'):
print(file)
with open(file, 'r') as fp:
new_lines = []
lines = fp.readlines()
fp.close()
for line in lines:
#查找文件路径,并在前面拼接上目录, 把repo补丁转换成可以直接在git上打的patch
if line.startswith('diff --git') or line.startswith('--- ') or line.startswith('+++ '):
#print(line)
new_line = re.sub(' a/', ' a/' + log['path'] + '/', line)
new_line = re.sub(' b/', ' b/' + log['path'] + '/', new_line)
#print(new_line)
new_lines.append(new_line)
else:
new_lines.append(line)
patch_name = os.path.join(outdir, file)
with open(patch_name, 'w') as new_fp:
print(patch_name)
new_fp.writelines(new_lines)
new_fp.close()
try:
do_popen('rm ./*.patch ')
except Exception as e:
print('')
if __name__ == '__main__':
"""
通过repo获取到两个时间段的提交git log, 再通过git log获取patch
"""
# 生成的patch放在当前目录的patchs中
patch_dir = os.path.join(os.getcwd(), 'patchs')
if not os.path.exists(patch_dir):
os.mkdir(patch_dir)
else:
try:
# 先删除旧的patch
do_popen('rm ' + patch_dir + './*.patch ')
except Exception as e:
print('')
#得到两个repo快照间的git修改的log
logs = get_diff_git_log()
for log in logs:
# 遍历git log进入到实际的子git目录中生成patch
old_dir = os.getcwd()
os.chdir(log['path'])
print(log['path'])
# 把所有的子git中的修改制作成patch放到patchs目录下
get_format_patch(log, patch_dir)
os.chdir(old_dir)
作者:帅得不敢出门 csdn原创谢绝转载