IntelliJ IDEA下基于Scala实现的Git检查工具

news2024/11/17 13:48:51

图片

本文使用Scala实现自定义的Git检查工具,读者可以基于本文的示例进行扩展与实现,也可以进行其他应用方向的尝试。

01、Git检查工具

在实现Git检查工具之前需要知道程序究竟要做什么。我们知道,在管理Git分支时可以进行代码合并操作,这样可以将其他开发者提交的内容同步到当前分支中,当用户对自己的分支进行提交时就不会与现有版本产生冲突。

反向合并也可以理解为一种回合,在用户使用GitLab等版本管理软件时经常会出现这种现象,但是反向合并带来了十分严重的问题: 代码污染。

可以这样理解,用户分支是介于生产分支与测试分支中间的媒介,它必须保证与两种分支的匹配性问题,即文件差异性问题。通常用户分支是基于生产拉取出来的全新分支,而很多开发者都试图使用这个分支进行修改并提交到测试分支进行测试发布。

在理想情况下项目的测试分支与生产分支应该是一致的,因此反向合并容易被修改或纠正,但是在测试分支与生产分支差异较大的时候,反向合并会将测试分支中的内容合并到用户分支中,如果用户分支被提交到生产分支上,则将会产生不可恢复的灾难。

基于上述原因,我们使用Scala设计一款简单的检查工具,它可以检查指定分支或分支组中所有的提交信息,并从这些信息中过滤出带有回合操作的历史。

如果发生过反向合并的操作,则在Git提交历史记录中通常会带有Mergeremotetrackingbranch...的字样信息,但是带有这种信息的提交并不一定都产生了合并问题。

当通过Git检查工具过滤出符合上述特征的分支后,可以通过判断与生产分支的差异数量并设定一个判断阈值的方式再次深度过滤或直接人工观察用户分支的差异化等多种方式来确保上线分支的准确性。

02、编写配置

在Git版本控制管理章节里提到过,反向合并会对开发者的项目分支带来污染,因此可以实现一个用于Git分支检查的工具,这样在每次例行版本维护时可以帮助我们快速定位反向合并的问题。

工具不一定能解决所有的问题,因为每个问题的出现都有其随机性,但是工具却能从某些方面提升我们的效率。读者在学习完本章后,可以根据需要自行扩展并定制更多的功能。

首先在resources资源目录下,创建一个名为config.conf的文件,它用于Git检查工具的基础配置。config.conf配置文件中定义了本地Git项目的根目录及待检查的分支,代码如下:

{
  group1 = {
    workDir = "Git项目目录"
  }
  group2 = {
    workDir = "Git项目目录"
    base = master
    branches = [
      user_local_branch
    ]
  }
}

 

在上述配置中对待检查目标进行了分组,运行时用户可以将需要对比的项目及分支预先定义好,这样可以在项目启动后通过接收参数的方式来动态调整使用哪一组配置进行目标分支的检查与分析。

在每一组配置里,workDir指定本地Git项目的根目录。base用于指定项目的主分支(master)。branches是一个分支列表,它代表了待检查的分支,这些分支既可以是本地分支,也可以是远程分支。如果是远程分支,则通常要在其前面添加origin/前缀。

接下来定义一个用于控制日志输出的配置文件,代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <properties>
        <property name="APP_HOME">$${env:APP_HOME}</property>
        <property name="LOG_HOME">${APP_HOME}/logs</property>
        <property name="mainFilename">${LOG_HOME}/vh.log</property>
    </properties>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT" follow="true">
            <PatternLayout pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level - %msg%n" />
        </Console>
        <RollingFile name="FileMain" fileName="${mainFilename}"
                     filePattern="${LOG_HOME}/vh%date{yyyyMMdd}_%i.log.gz">
            <PatternLayout>
                <pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %level - %msg%n</pattern>
            </PatternLayout>
            <Policies>
                <CronTriggeringPolicy schedule="0 0 0 * * ?" evaluateOnStartup="true"/>
                <SizeBasedTriggeringPolicy size="20 MB" />
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console" />
            <AppenderRef ref="FileMain" />
        </Root>
    </Loggers>
</Configuration>

03、编写启动程序

接下来编写项目的启动程序,启动程序可以接收外界传入的参数以实现不同配置的切换使用,代码如下:

package com.scala.git
import org.slf4j.LoggerFactory

object MainCheck {
  private val log = LoggerFactory.getLogger(getClass)
  def main(args: Array[String]): Unit = {
    log.info(s"接收外界传递的切换配置: ${args.group}")
    var group = "group2"
    if(args.length > 0){
      group = args(0)
    }
    log.info(s"当前配置为$group")
    group match {
      case "group2" => CheckTask.main(args)
      case _ => log.error(s"not found $group")
    }
  }
}

 

因为Scala程序可以与Java语言混合编写,因此Java开发人员在阅读Scala程序时相对容易理解一些。

在MainCheck对象的主方法中接收了外界传递进来的group参数,它可以在程序启动时动态传递到主方法中并替代默认配置组group2。

接下来通过match操作对group变量所代表的分组配置进行匹配,如果匹配成功,则执行对应用的功能调用。如果匹配不上,则输出日志提示。

04、编写校验逻辑

在MainCheck.scala应用程序中,当外界变量group匹配成功后会调用具体的执行逻辑,此逻辑封装在CheckTask对象方法中。

在编写CheckTask对象之前先来编写GitUtil.scala程序文件,其作用为调用并执行CMD命令以便获取指定分支的所有提交信息,这些提交信息将以数组的形式返回,代码如下:

package com.scala.util
import java.io.File
import org.slf4j.LoggerFactory

import scala.sys.process.{Process, ProcessLogger}

object GitUtil {
  private val isWin = System.getProperty("os.name").toLowerCase.contains("Windows")
  private val log = LoggerFactory.getLogger(getClass)

  def getCommits(from: String, to: String, workDir: String): String = {
    val cols = Array("%H", "%s", "%an", "%ae", "%ci")
    val tem = from + ".." + to + " --pretty=format:\"" + cols.mkString("/") + "\"";
    val value = cmdCommits(s"git log " + tem, new File(workDir))
    value
  }

  def cmdCommits(cmd: String, workDir: File): String = {
    var commits:Array[String] = null;
    if(!isWin){
      commits = cmd.split("\\s")
    }else{
      commits = Array("cmd", "/c") ++ cmd.split("\\s")
    }
    Process(commits, workDir).!!(ProcessLogger(s => log.error(s"err => $s")))
  }
}

 接下来实现CheckTask.scala程序文件,代码如下:

package com.scala.git

import com.scala.util.GitUtil
import com.typesafe.config.ConfigFactory
import scala.collection.JavaConverters._

object CheckTask {

  private val config = ConfigFactory.load("config.conf").getConfig("group2")
  private val orderWorkDir = config.getString("workDir");
  private val base = config.getString("base");
  private val branchs = config.getStringList("branchs");

  def main(args: Array[String]): Unit = {
    println(s"参照对比分支[$base]")
    println(s"待检查分支集合$branchs")
    checkBraches(base, asScalaBuffer(branchs).toArray).foreach(b => println(s"发现可疑分支 $b"))
  }
  
  def checkBraches(base: String, brans: Array[String]): Array[String] = {
    brans.filter(b => checkMergeError(base, b))
  }

  private def checkMergeError(base: String, target: String): Boolean = {
        println(s"对比分支:$base,检查分支:$target")
        //取得所有提交信息
        val commits = getDiffCommits(base, target)
        //从历史提交记录过滤出回合过的分支
        val targets = commits.filter(isMergeReverse)
        targets.foreach(c => {println(c.mkString("\t"))})
        println(s"分支[$target]中可疑提交次数: ${targets.length}")
        targets.length != 0
  }

  private def isMergeReverse(messages: Array[String]): Boolean = {
    val msg = messages(1)
    if(msg.startsWith("Merge branch 'int_") || msg.startsWith("Merge remote-tracking branch ")){
      val splits = msg.split("\\s")
      val end = splits(splits.length-1)
      val flag = end.startsWith("int_") || end.startsWith("local_int_")
      return !flag
    }
    false
  }

  private def getDiffCommits(from: String, to: String): Array[Array[String]] = {
    GitUtil.getCommits(from, to, orderWorkDir).lines.map(_.split("/")).toArray
  }
}

现在尝试运行工具,随便选取系统中的某个Git项目并修改config.conf配置文件以使其与Git项目中的分支对应,然后运行MainCheck.scala程序文件,运行效果如图1所示。

图片

■ 图1 运行Git检查工具

 

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/906264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cloud 问题

eureka 自我保护机制 eureka 是定时去拿 统计最近15分钟的eureka实例正常的心跳占比&#xff0c;如果低于85%&#xff0c;那么就会触发自我保护机制。 触发了自我保护机制&#xff0c;eureka 暂时会把失效的服务保护起来&#xff0c;不让其过期&#xff0c;但是这些服务也不是…

Amazon S3 对象存储Java API操作记录(Minio与S3 SDK两种实现)缘起

缘起 今年(2023年) 2月的时候做了个适配Amazon S3对象存储接口的需求&#xff0c;由于4月份自学考试临近&#xff0c;一直在备考就拖着没总结记录下&#xff0c;开发联调过程中也出现过一些奇葩的问题&#xff0c;最近人刚从考试缓过来顺手记录一下。 S3对象存储的基本概念 …

Git:本地仓库创建和远程绑定

创建远程仓库 登录git网站&#xff0c;创建一个远程仓库 创建时可以选择仓库属性&#xff0c;公共/私有。仓库命名之类。创建完毕后可以在网站上看到仓库所在网址。 创建本地仓库 打开一个文件夹&#xff0c;鼠标右键Git Bash Here&#xff0c;打开git的命令行 git init//…

什么是室温超导?室温超导意味着什么?

前言&#xff1a; 7月22日&#xff0c;韩国一个科学团队发布论文声称“实现了室温超导”&#xff0c;引发了全球关注&#xff0c;全球很多科学实验室都开始着手按照论文来进行实验&#xff0c;尝试验证论文的真实性&#xff0c;因为如果真的可以实现室温超导&#xff0c;那么影…

REI EDI 项目测试流程

在此前的文章REI EDI 项目案例中&#xff0c;我们了解了REI EDI项目的需求以及实现&#xff0c;项目中采用的是知行之云 LIP 解决方案&#xff0c;供应商需要接收来自 REI 的 EDI 850采购订单、EDI 860 采购订单变更&#xff0c;向REI发送 EDI 856 提前发货通知以及EDI 810发票…

【C语言】选择排序

基本原理 先找到数组中最大的那个数&#xff0c;将最大的数放到数组最右端&#xff08;交换a[maxid]和a[len-1]这两个数的位置&#xff09;&#xff0c;然后继续从a[0]到a[len-2]中找到最大的数&#xff0c;然后交换a[maxid]和a[len-2]位置&#xff0c;依次查找交换&#xff0c…

Golang gorm many2many查询

多对多关系 多对多关系&#xff0c;需要用第三张表存储两张表的关系 多对多就必须得加上many2many的tag。article_tags是用来指定第三张表&#xff0c; package mainimport ("gorm.io/driver/mysql""gorm.io/gorm" )type Tag struct {ID uintName …

如何选择适合你的开源电商 ERP 系统

在这篇文章中&#xff0c;我们将分享一些有用的提示&#xff0c;帮助你在选择开源电商 ERP 系统时做出明智的决定。 开源电商 ERP 系统的重要性 开源电商 ERP 系统可以帮助你管理库存、订单和客户信息&#xff0c;使你的业务更加高效和可靠。与传统的ERP系统相比&#xff0c;…

打造全球浪漫:2023七夕节出海品牌的国际化营销创意

随着时间的流转&#xff0c;2023年的七夕节即将到来&#xff0c;这是一年一度的浪漫佳节&#xff0c;被众多情侣们期待已久。而对于出海品牌来说&#xff0c;七夕节不仅是一个传统的节日&#xff0c;更是一个极具营销价值的时刻。在这个浪漫的节日里&#xff0c;出海品牌可以借…

一文学会lua脚本

文章目录 0.前言背景应用 1. 学习大纲1. 学习基本语法&#xff1a;2. 理解函数和模块&#xff1a;3. 深入数据结构&#xff1a;4. 高级特性和技巧&#xff1a;5. 实践项目&#xff1a; 2. Lua脚本2.1 学习基本语法2.2 理解函数和模块2.3 深入数据结构2.4 高级特性和技巧 3. 高级…

无涯教程-PHP - XML GET

XML Get已用于从xml文件获取节点值。以下示例显示了如何从xml获取数据。 Note.xml 是xml文件&#xff0c;可以通过php文件访问。 <SUBJECT><COURSE>Android</COURSE><COUNTRY>India</COUNTRY><COMPANY>LearnFk</COMPANY><PRICE…

从月薪2300到年薪180万,流水线厂妹变身谷歌工程师,她靠什么逆天改命?

近日&#xff0c;一个90后女孩孙玲收到了谷歌的offer&#xff0c;年薪总包180万的她&#xff0c;顺利进阶为外界眼中闪闪发光的“高收入群体”。 她来自农村&#xff0c;曾2次被迫辍学。 好不容易争取到上学的机会&#xff0c;高考却只考了399分&#xff0c;没有大学可上。 …

Vulnhub系列靶机---Infosec_Warrior1

InfoSecWarrior CTF 2020: 01官网地址 难易程度&#xff1a;So Easy 信息收集 主机发现 arp-scan -l端口扫描 nmap -A -p- 192.168.80.145目录爆破 dirsearch -u 192.168.80.145 -i 200访问80端口&#xff0c;只能看出是Apache站点&#xff0c;没有别的 访问一下sitemap.xm…

【前端工程师必备-UI设计师必备-素材图片资源网站】免费图标网站、免费图片素材网站、UI作品大全、渐变色生成工具(css样式代码+图片素材)、免费矢量图

【前端工程师必备-素材图片资源网站】免费图标网站、免费图片素材网站、UI作品大全、渐变色生成工具&#xff08;css样式代码图片素材&#xff09;、免费矢量图 一、免费图标网站集合1、iconfont2、iconfinder3、icons8 二、免费图片素材网站1、mixkit2、菜鸟图库 三、免费矢量…

linux 移动mv命令(实战案例)

linux 移动命令&#xff08;你真的会用吗&#xff1f;&#xff1f;&#xff1f;&#xff09; 第一种情况&#xff1a;移动文件 例如&#xff1a; 将/gdda_file 文件下的 zlib-devel-1.2.7-18el7.x86_64.rpm 移动到 /root/ces/tools文件下 解决方法&#xff1a; mv /gdda_fi…

Linux 系统的如何优化(面试题)

Linux 系统的如何优化&#xff08;面试题&#xff09; (1) 禁用不需要的服务 ntsysv 命令最为方便&#xff0c;执行后&#xff0c;把不需要的勾选去掉就行 &#xff08;2&#xff09;避免直接使用root用户&#xff0c;普遍用户通过sudo授权操作 &#xff08;3&#xff09;通过…

redis 7高级篇1 redis的单线程与多线程

一 redis单线程与多线程 1.1 redis单线程&多线程 1.redis的单线程 redis单线程主要是指Redis的网络IO和键值对读写是由一个线程来完成的&#xff0c;Redis在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理…

ubuntu 20.04 安装 高版本cuda 11.7 和 cudnn最新版

一、安装显卡驱动 参考另一篇文章&#xff1a;Ubuntu20.04安装Nvidia显卡驱动教程_ytusdc的博客-CSDN博客 二、安装CUDA 英伟达官网&#xff08;最新版&#xff09;&#xff1a;CUDA Toolkit 12.2 Update 1 Downloads | NVIDIA Developer CUDA历史版本下载地址&#xff1a;C…

上网课用什么耳机和麦克风,分享几款骨传导耳机上网课用

各位耳机狂热者&#xff0c;咱们都了解传统的蓝牙耳机相对于老式有线耳机来说确实方便得多。但是&#xff0c;也别忘了蓝牙耳机会导致耳道不断堵塞&#xff0c;引发细菌滋生等问题。好在近年来&#xff0c;骨传导耳机如火如荼地走红&#xff0c;解决了这些难题&#xff0c;简直…

selenium Chrome驱动下载地址

Chrome驱动官方最新版下载地址:https://googlechromelabs.github.io/chrome-for-testing/ 有稳定版&#xff0c;开发版等版本可以选择下载 选择 操作系统复制下载链接直接下载