repo的patch转换成git am能打的patch

安卓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

python 复制代码
# 作者帅得不敢出门
# -*- 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原创谢绝转载

相关推荐
和你一起去月球9 小时前
TypeScript - 函数(下)
javascript·git·typescript
我不是程序猿儿10 小时前
【GIT】TortoiseGit的变基(Rebase)操作
git
yyycqupt16 小时前
git使用(一)
git
Kkooe20 小时前
GitLab|数据迁移
运维·服务器·git
Beekeeper&&P...21 小时前
git bash是什么,git是什么,git中的暂存区是什么,git中的本地仓库是什么,git中工作目录指的是什么
开发语言·git·bash
Stara05111 天前
Git推送+拉去+uwsgi+Nginx服务器部署项目
git·python·mysql·nginx·gitee·github·uwsgi
lsswear1 天前
GIT 操作
git
勋勋勋勋小勋勋1 天前
git分支合并某一次提交
git
PandaCave1 天前
git常用命令以及注意事项总结
git