IntelliJ IDEA基于Scala實(shí)現(xiàn)Git檢查工具
01、Git檢查工具
在實(shí)現(xiàn)Git檢查工具之前需要知道程序究竟要做什么。我們知道,在管理Git分支時(shí)可以進(jìn)行代碼合并操作,這樣可以將其他開(kāi)發(fā)者提交的內(nèi)容同步到當(dāng)前分支中,當(dāng)用戶(hù)對(duì)自己的分支進(jìn)行提交時(shí)就不會(huì)與現(xiàn)有版本產(chǎn)生沖突。
反向合并也可以理解為一種回合,在用戶(hù)使用GitLab等版本管理軟件時(shí)經(jīng)常會(huì)出現(xiàn)這種現(xiàn)象,但是反向合并帶來(lái)了十分嚴(yán)重的問(wèn)題: 代碼污染。
可以這樣理解,用戶(hù)分支是介于生產(chǎn)分支與測(cè)試分支中間的媒介,它必須保證與兩種分支的匹配性問(wèn)題,即文件差異性問(wèn)題。通常用戶(hù)分支是基于生產(chǎn)拉取出來(lái)的全新分支,而很多開(kāi)發(fā)者都試圖使用這個(gè)分支進(jìn)行修改并提交到測(cè)試分支進(jìn)行測(cè)試發(fā)布。
在理想情況下項(xiàng)目的測(cè)試分支與生產(chǎn)分支應(yīng)該是一致的,因此反向合并容易被修改或糾正,但是在測(cè)試分支與生產(chǎn)分支差異較大的時(shí)候,反向合并會(huì)將測(cè)試分支中的內(nèi)容合并到用戶(hù)分支中,如果用戶(hù)分支被提交到生產(chǎn)分支上,則將會(huì)產(chǎn)生不可恢復(fù)的災(zāi)難。
基于上述原因,我們使用Scala設(shè)計(jì)一款簡(jiǎn)單的檢查工具,它可以檢查指定分支或分支組中所有的提交信息,并從這些信息中過(guò)濾出帶有回合操作的歷史。
如果發(fā)生過(guò)反向合并的操作,則在Git提交歷史記錄中通常會(huì)帶有Mergeremotetrackingbranch...的字樣信息,但是帶有這種信息的提交并不一定都產(chǎn)生了合并問(wèn)題。
當(dāng)通過(guò)Git檢查工具過(guò)濾出符合上述特征的分支后,可以通過(guò)判斷與生產(chǎn)分支的差異數(shù)量并設(shè)定一個(gè)判斷閾值的方式再次深度過(guò)濾或直接人工觀察用戶(hù)分支的差異化等多種方式來(lái)確保上線(xiàn)分支的準(zhǔn)確性。
02、編寫(xiě)配置
在Git版本控制管理章節(jié)里提到過(guò),反向合并會(huì)對(duì)開(kāi)發(fā)者的項(xiàng)目分支帶來(lái)污染,因此可以實(shí)現(xiàn)一個(gè)用于Git分支檢查的工具,這樣在每次例行版本維護(hù)時(shí)可以幫助我們快速定位反向合并的問(wèn)題。
工具不一定能解決所有的問(wèn)題,因?yàn)槊總€(gè)問(wèn)題的出現(xiàn)都有其隨機(jī)性,但是工具卻能從某些方面提升我們的效率。讀者在學(xué)習(xí)完本章后,可以根據(jù)需要自行擴(kuò)展并定制更多的功能。
首先在resources資源目錄下,創(chuàng)建一個(gè)名為config.conf的文件,它用于Git檢查工具的基礎(chǔ)配置。config.conf配置文件中定義了本地Git項(xiàng)目的根目錄及待檢查的分支,代碼如下:
{ group1 = { workDir = "Git項(xiàng)目目錄" } group2 = { workDir = "Git項(xiàng)目目錄" base = master branches = [ user_local_branch ] } }
在上述配置中對(duì)待檢查目標(biāo)進(jìn)行了分組,運(yùn)行時(shí)用戶(hù)可以將需要對(duì)比的項(xiàng)目及分支預(yù)先定義好,這樣可以在項(xiàng)目啟動(dòng)后通過(guò)接收參數(shù)的方式來(lái)動(dòng)態(tài)調(diào)整使用哪一組配置進(jìn)行目標(biāo)分支的檢查與分析。
在每一組配置里,workDir指定本地Git項(xiàng)目的根目錄。base用于指定項(xiàng)目的主分支(master)。branches是一個(gè)分支列表,它代表了待檢查的分支,這些分支既可以是本地分支,也可以是遠(yuǎn)程分支。如果是遠(yuǎn)程分支,則通常要在其前面添加origin/前綴。
接下來(lái)定義一個(gè)用于控制日志輸出的配置文件,代碼如下:
<?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、編寫(xiě)啟動(dòng)程序
接下來(lái)編寫(xiě)項(xiàng)目的啟動(dòng)程序,啟動(dòng)程序可以接收外界傳入的參數(shù)以實(shí)現(xiàn)不同配置的切換使用,代碼如下:
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"當(dāng)前配置為$group") group match { case "group2" => CheckTask.main(args) case _ => log.error(s"not found $group") } } }
因?yàn)镾cala程序可以與Java語(yǔ)言混合編寫(xiě),因此Java開(kāi)發(fā)人員在閱讀Scala程序時(shí)相對(duì)容易理解一些。
在MainCheck對(duì)象的主方法中接收了外界傳遞進(jìn)來(lái)的group參數(shù),它可以在程序啟動(dòng)時(shí)動(dòng)態(tài)傳遞到主方法中并替代默認(rèn)配置組group2。
接下來(lái)通過(guò)match操作對(duì)group變量所代表的分組配置進(jìn)行匹配,如果匹配成功,則執(zhí)行對(duì)應(yīng)用的功能調(diào)用。如果匹配不上,則輸出日志提示。
04、編寫(xiě)校驗(yàn)邏輯
在MainCheck.scala應(yīng)用程序中,當(dāng)外界變量group匹配成功后會(huì)調(diào)用具體的執(zhí)行邏輯,此邏輯封裝在CheckTask對(duì)象方法中。
在編寫(xiě)CheckTask對(duì)象之前先來(lái)編寫(xiě)GitUtil.scala程序文件,其作用為調(diào)用并執(zhí)行CMD命令以便獲取指定分支的所有提交信息,這些提交信息將以數(shù)組的形式返回,代碼如下:
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"))) } }
接下來(lái)實(shí)現(xiàn)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"參照對(duì)比分支[$base]") println(s"待檢查分支集合$branchs") checkBraches(base, asScalaBuffer(branchs).toArray).foreach(b => println(s"發(fā)現(xiàn)可疑分支 $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"對(duì)比分支:$base,檢查分支:$target") //取得所有提交信息 val commits = getDiffCommits(base, target) //從歷史提交記錄過(guò)濾出回合過(guò)的分支 val targets = commits.filter(isMergeReverse) targets.foreach(c => {println(c.mkString("\t"))}) println(s"分支[$target]中可疑提交次數(shù): ${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 } }
現(xiàn)在嘗試運(yùn)行工具,隨便選取系統(tǒng)中的某個(gè)Git項(xiàng)目并修改config.conf配置文件以使其與Git項(xiàng)目中的分支對(duì)應(yīng),然后運(yùn)行MainCheck.scala程序文件,運(yùn)行效果如圖1所示。
圖1 運(yùn)行Git檢查工具
以上就是IntelliJ IDEA基于Scala實(shí)現(xiàn)Git檢查工具的詳細(xì)內(nèi)容,更多關(guān)于IntelliJ IDEA Scala的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot+mybatis配置控制臺(tái)打印sql日志的方法
這篇文章主要介紹了springboot+mybatis配置控制臺(tái)打印sql日志的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08java解析XML Node與Element的區(qū)別(推薦)
下面小編就為大家分享一篇java解析XML Node與Element的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01servlet下載文件實(shí)現(xiàn)代碼詳解(五)
這篇文章主要為大家詳細(xì)介紹了servlet下載文件的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09spring boot配合前端實(shí)現(xiàn)跨域請(qǐng)求訪(fǎng)問(wèn)
本篇文章主要介紹了spring boot配合前端實(shí)現(xiàn)跨域請(qǐng)求訪(fǎng)問(wèn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04Spring?AOP?創(chuàng)建代理對(duì)象詳情
這篇文章介紹了Spring?AOP?創(chuàng)建代理對(duì)象詳情,主要介紹AOP?創(chuàng)建代理對(duì)象和上下文相關(guān)的內(nèi)容,下文分享具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-05-05java調(diào)用ffmpeg實(shí)現(xiàn)視頻轉(zhuǎn)換的方法
這篇文章主要介紹了java調(diào)用ffmpeg實(shí)現(xiàn)視頻轉(zhuǎn)換的方法,較為詳細(xì)分析了java視頻格式轉(zhuǎn)換所需要的步驟及具體實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-06-06Java通過(guò)Lambda函數(shù)的方式獲取屬性名稱(chēng)
這篇文章主要介紹了通過(guò)Lambda函數(shù)的方式獲取屬性名稱(chēng),實(shí)現(xiàn)步驟是通過(guò)定義一個(gè)函數(shù)式接口, 用來(lái)接收l(shuí)ambda方法引用,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10Java使用modbus4j實(shí)現(xiàn)modbus?tcp通訊
Modbus是由Modicon(現(xiàn)為施耐德電氣公司的一個(gè)品牌)在1979年發(fā)明的,是全球第一個(gè)真正用于工業(yè)現(xiàn)場(chǎng)的總線(xiàn)協(xié)議,本文主要介紹了java如何使用modbus4j實(shí)現(xiàn)modbus?tcp通訊,感興趣的可以了解下2023-12-12關(guān)于Linux服務(wù)器配置java環(huán)境遇到的問(wèn)題小結(jié)
這篇文章主要介紹了關(guān)于Linux服務(wù)器配置java環(huán)境遇到的問(wèn)題小結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12基于SpringBoot整合oauth2實(shí)現(xiàn)token認(rèn)證
這篇文章主要介紹了基于SpringBoot整合oauth2實(shí)現(xiàn)token 認(rèn)證,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01