当前位置: 首页 > article >正文

【Python】快速判断两个commit 是否存在cherry-pick 关系

判断两个提交是否有 cherry-pick 关系的 Python 脚本,可以基于以下三种常见情况进行优化:

  1. Commit Hash 一致:如果两个提交的 hash 完全相同,那么它们是相同的提交。

  2. Commit Title 存在关联:如果两个提交的 commit message 提及了相同的原始提交,例如 cherry picked from commit <hash>,可以通过解析提交信息来确定关联。

  3. Commit 变更内容一致:即使 hashtitle 不同,如果两个提交的代码变更完全一致,则可能是 cherry-pick 关系。

另外,还有可能存在其他场景,比如提交的父节点不同,但内容一致,这也是一种 cherry-pick 的表现。

基于以上情况,下面是一个优化的 Python 脚本:

Python 脚本

V1版本
import subprocess
import re

def run_git_command(args):
    """
    运行 Git 命令并返回输出结果。
    """
    try:
        result = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        if result.returncode != 0:
            print(f"Error running command {args}: {result.stderr}")
            return None
        return result.stdout.strip()
    except Exception as e:
        print(f"An error occurred: {e}")
        return None

def get_commit_message(commit_hash):
    """
    获取提交信息(commit message)。
    """
    return run_git_command(["git", "log", "-1", "--pretty=%B", commit_hash])

def get_diff(commit_hash):
    """
    获取提交的代码差异(diff)。
    """
    return run_git_command(["git", "diff-tree", "--no-commit-id", "--patch", "-r", commit_hash])

def check_cherry_pick_message(commit1_message, commit2_message):
    """
    检查提交信息中是否提到 cherry-pick 的关联。
    """
    cherry_pick_pattern = re.compile(r'cherry\s+picked\s+from\s+commit\s+([a-f0-9]{40})')
    
    # 检查第一个提交信息是否提到 cherry-pick 的原始提交
    match1 = cherry_pick_pattern.search(commit1_message)
    match2 = cherry_pick_pattern.search(commit2_message)
    
    if match1 and match2 and match1.group(1) == match2.group(1):
        return True
    
    # 或者检查一个提交是否提到另一个提交
    if match1 and match1.group(1) in commit2_message:
        return True
    if match2 and match2.group(1) in commit1_message:
        return True
    
    return False

def compare_commit_diffs(commit1, commit2):
    """
    比较两个提交的代码变更是否一致。
    """
    diff1 = get_diff(commit1)
    diff2 = get_diff(commit2)
    
    if diff1 is None or diff2 is None:
        return False
    
    return diff1 == diff2

def compare_commits(commit1, commit2):
    """
    综合比较两个提交是否有 cherry-pick 关系。
    """
    # 1. 检查 commit hash 是否相同
    if commit1 == commit2:
        print(f"Commits {commit1} and {commit2} are identical (same hash).")
        return True
    
    # 2. 检查 commit message 是否提到 cherry-pick 关系
    commit1_message = get_commit_message(commit1)
    commit2_message = get_commit_message(commit2)
    
    if commit1_message is None or commit2_message is None:
        print("Failed to get commit messages.")
        return False
    
    if check_cherry_pick_message(commit1_message, commit2_message):
        print(f"Commits {commit1} and {commit2} have a cherry-pick relation based on commit message.")
        return True
    
    # 3. 检查代码变更是否完全一致
    if compare_commit_diffs(commit1, commit2):
        print(f"Commits {commit1} and {commit2} have identical code changes (cherry-pick relation likely).")
        return True
    
    print(f"Commits {commit1} and {commit2} do not have a clear cherry-pick relation.")
    return False

if __name__ == "__main__":
    # 输入需要比较的两个 commit hash
    commit_hash_1 = input("Enter the first commit hash: ")
    commit_hash_2 = input("Enter the second commit hash: ")

    if compare_commits(commit_hash_1, commit_hash_2):
        print(f"Commits {commit_hash_1} and {commit_hash_2} are related (cherry-pick detected).")
    else:
        print(f"Commits {commit_hash_1} and {commit_hash_2} are not related (no cherry-pick detected).")

如果存在编码错误

可以使用下方脚本尝试

V2版本
import subprocess
import re

def run_git_command(args):
    """
    运行 Git 命令并返回输出结果。
    """
    try:
        result = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, encoding='utf-8')
        if result.returncode != 0:
            print(f"Error running command {args}: {result.stderr}")
            return None
        return result.stdout.strip()
    except Exception as e:
        print(f"An error occurred: {e}")
        return None

def get_commit_message(commit_hash):
    """
    获取提交信息(commit message)。
    """
    return run_git_command(["git", "log", "-1", "--pretty=%B", commit_hash])

def get_diff(commit_hash):
    """
    获取提交的代码差异(diff)。
    """
    try:
        return run_git_command(["git", "diff-tree", "--no-commit-id", "--patch", "-r", commit_hash])
    except Exception as e:
        print(f"An error occurred while getting diff for {commit_hash}: {e}")
        return None

def check_cherry_pick_message(commit1_message, commit2_message):
    """
    检查提交信息中是否提到 cherry-pick 的关联。
    """
    cherry_pick_pattern = re.compile(r'cherry\s+picked\s+from\s+commit\s+([a-f0-9]{40})')
    
    match1 = cherry_pick_pattern.search(commit1_message)
    match2 = cherry_pick_pattern.search(commit2_message)
    
    if match1 and match2 and match1.group(1) == match2.group(1):
        return True
    
    if match1 and match1.group(1) in commit2_message:
        return True
    if match2 and match2.group(1) in commit1_message:
        return True
    
    return False

def compare_commit_diffs(commit1, commit2):
    """
    比较两个提交的代码变更是否一致。
    """
    diff1 = get_diff(commit1)
    diff2 = get_diff(commit2)
    
    if diff1 is None or diff2 is None:
        return False
    
    return diff1 == diff2

def compare_commits(commit1, commit2):
    """
    综合比较两个提交是否有 cherry-pick 关系。
    """
    if commit1 == commit2:
        print(f"Commits {commit1} and {commit2} are identical (same hash).")
        return True
    
    commit1_message = get_commit_message(commit1)
    commit2_message = get_commit_message(commit2)
    
    if commit1_message is None or commit2_message is None:
        print("Failed to get commit messages.")
        return False
    
    if check_cherry_pick_message(commit1_message, commit2_message):
        print(f"Commits {commit1} and {commit2} have a cherry-pick relation based on commit message.")
        return True
    
    if compare_commit_diffs(commit1, commit2):
        print(f"Commits {commit1} and {commit2} have identical code changes (cherry-pick relation likely).")
        return True
    
    print(f"Commits {commit1} and {commit2} do not have a clear cherry-pick relation.")
    return False

def validate_commit_hash(commit_hash):
    """
    验证提交 hash 是否是有效的 SHA-1 hash。
    """
    if re.fullmatch(r'[a-fA-F0-9]{40}', commit_hash):
        return True
    else:
        print(f"Invalid commit hash: {commit_hash}")
        return False

if __name__ == "__main__":
    commit_hash_1 = input("Enter the first commit hash: ")
    commit_hash_2 = input("Enter the second commit hash: ")

    if validate_commit_hash(commit_hash_1) and validate_commit_hash(commit_hash_2):
        if compare_commits(commit_hash_1, commit_hash_2):
            print(f"Commits {commit_hash_1} and {commit_hash_2} are related (cherry-pick detected).")
        else:
            print(f"Commits {commit_hash_1} and {commit_hash_2} are not related (no cherry-pick detected).")
    else:
        print("Please enter valid commit hashes.")

脚本的工作原理

  1. Commit Hash 一致:脚本首先检查两个提交的 hash 是否完全相同。如果相同,它们肯定是相同的提交。

  2. Commit Title 存在关联:通过正则表达式匹配 commit message 中的 cherry picked from commit <hash> 字符串,检查一个提交是否从另一个提交进行了 cherry-pick。如果 commit message 中存在这样的引用,则说明它们有 cherry-pick 关系。

  1. Commit 变更内容一致:如果提交的 hashmessage 没有明显的关联,脚本通过获取两个提交的代码变更(git diff-tree)并对比差异内容是否完全相同。如果两个提交的代码变更完全一致,它们很有可能是 cherry-pick 关系。

使用说明

  1. 将脚本保存为 compare_commits.py

  2. 在 Git 仓库的根目录执行以下命令:

     

    python3 compare_commits.py

  3. 输入两个需要比较的提交哈希(commit hash)。

处理的场景

  • 两个提交的 commit hash 完全相同(直接相同的提交)。

  • commit message 提到 cherry-pick 的引用关系。

  • commit hashcommit message 不同,但代码变更内容完全相同。

这个脚本可以帮助识别 cherry-pick 关系的多种常见情况,并可以扩展以处理更多特殊情况。你可以尝试运行这个脚本,看看能否正确检测出 cherry-pick 关系。

运行示例


http://www.kler.cn/news/317600.html

相关文章:

  • ubuntu查看全部的磁盘分区命令
  • ​智慧铜矿厂综合管控平台,智慧矿山数字孪生
  • 应用案例 | 使用dataFEED OPC Tunnel解决基于DCOM的OPC Classic通信难题
  • axios相关知识点
  • Hadoop三大组件之HDFS(一)
  • git remote
  • Transformers | 在自己的电脑上开启预训练大模型使用之旅!
  • 基于Spring Boot的宠物咖啡馆平台【附源码】
  • Ceph官方文档_01_Ceph简介
  • 构建数据分析模型,及时回传各系统监控监测数据进行分析反馈响应的智慧油站开源了。
  • 实时对话翻译软件
  • 【Linux】解锁管道通信和共享内存通信,探索进程间通信的海洋
  • 显示屏显示缺陷检测系统源码分享
  • GEE教程:利用NASA的SMAP(Soil Moisture Active Passive)数据计算2020-2024年的时序土壤湿度分析
  • OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【扩展组件】上
  • 【Power Compiler手册】13.UPF多电压设计实现(7)
  • GPU共享技术深度剖析与总结
  • css禁止图片保存,CSS中的图片保存方法
  • 【逻辑回归+实战】
  • LLM安全风险及应对
  • Android CarrierConfig 配置问题的解决流程
  • QT编译之后的debug包下运行程序双击运行出现无法定位程序输入点__gxx_personlity_seh0于动态链接库
  • Linux:文件描述符详解
  • react 常用hooks封装--useReactive
  • 全栈开发(五):初始化前端项目(nuxt3+vue3+element-plus)+前端代理
  • 【JVM】JVM执行流程和内存区域划分
  • 安卓13删除下拉栏中的设置按钮 android13删除设置按钮
  • 51单片机快速入门之按键应用拓展
  • Python编码系列—Python桥接模式:连接抽象与实现的桥梁
  • 如何进入电脑BIOS