通過 python 獲取一個 git commit 的改動行信息


前置知識

  • git diff 命令可以用來查看某個 commit 的改動信息。具體詳細的用法可以參考 git-diff 中的介紹。有一個命令 git diff HEAD^ HEAD 可以輸出當前的 commit 的改動內容。
    • 其中輸出的改動內容是有一定的格式的。對本次改動影響的文件,會包含如下信息:
      • 本次改動之前的的文件名
      • 本次改動之后的文件名
      • 本次改動的
  • python 可以同步執行一個 shell 命令,並獲得命令的輸出。

代碼

直接貼代碼了,可以通過下面的 python 方法獲取到(執行 prepareInfomation 方法,返回的):

import os
import re
from typing import *
import subprocess

class ChangedLineInfo:
    def __init__(self):
        self.changedLineNumbers = set()

    def addChangeInfo(self, startLine: int, lineCount: int):
        """
        補充改變的行號信息,
        startLine : 表示從該行起始有改變。
        lineCount : 表示從改行起,有多少行被改變了。
        """
        endLine = startLine + lineCount
        if (endLine < startLine):
            return
        for i in range(startLine, endLine):
            self.changedLineNumbers.add(i)

    def isLineChanged(self, line: int) -> bool:
        return line in self.changedLineNumbers

def getChangedLineInfoFromDiffLines(lines: List[str]) -> ChangedLineInfo:
    """
    該方法計算出 ,返回一個 ChangedLineInfo 對象
    參數 : lines , git-diff 命令輸出的,對一個文件的描述
    返回 : 返回一個ChangedLineInfo, 表示從 lines 中解析出來的 改變了的行 的信息。
    """
    changedLineInfo = ChangedLineInfo()
    # 根據 "@@ @@" 獲取改變行信息
    # 匹配到的 [0] : ","+從此處起始的刪除行數; [1] : 從此處新增的行數起始行; [2] : ","+從此處新增的行數數量
    reg = re.compile("^@@ -[0-9]+(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@")
    for line in lines:
        r = reg.findall(line)
        if len(r) > 0:
            changedLineStart = int(r[0][1])
            caughtLineCountStr = r[0][2]
            if len(caughtLineCountStr) > 0:
                changedLineCount = int(caughtLineCountStr[1:])
            else:
                changedLineCount = 1
            changedLineInfo.addChangeInfo(changedLineStart, changedLineCount)
    return changedLineInfo



def prepareInfomation():
    """
    執行一些操作,准備好數據並且返回:
    :return: 一個 map, key 為本次 commit 導致的"非刪除文件"的路徑(相對於 git 倉庫的路徑); value 為 ChangedInfo 對象,表示該文件的改動行信息.
    """
    gitCmd = "git diff --unified=0 --diff-filter=d HEAD~1 HEAD"
    gitDiffOutputRaw = subprocess.check_output(gitCmd.split(" "))
    outputStr = gitDiffOutputRaw.decode('utf-8')
    diffOutputLines = outputStr.splitlines()

    map = {}
    # 匹配到這個的一行表示開始結果開始展示 一個新的文件的 diff 信息,匹配到的信息 [0] 表示文件名
    # !!!!!!!!!! 忽略帶有空格的文件名的處理, 對於帶有空格的文件名,該檢測會出錯.但是暫時忽略
    separateLineReg = re.compile("^diff --git a/\S+ b/(\S+)")
    currentCheckFileName = ""
    diffLinesForCurrentCheckFile = []
    for i in range(len(diffOutputLines)):
        l = diffOutputLines[i]
        # 如果當前匹配到了 separateLine ,則
        # 1. 解析 diffLinesForCurrentCheckFile,並且將 { currentCheckFileName : 解析后的信息} 加入到 map 中;
        # 2. 更新當前的 currentCheckFileName ; 清空 diffLinesForCurrentCheckFile
        # 如果未匹配到,加入 diffLinesForCurrentCheckFile , 繼續下一行
        separateLineMatchResult = separateLineReg.findall(l)
        if len(separateLineMatchResult) > 0:
            if len(diffLinesForCurrentCheckFile) > 0:
                a = getChangedLineInfoFromDiffLines(diffLinesForCurrentCheckFile)
                map[currentCheckFileName] = a
                diffLinesForCurrentCheckFile.clear()
            # 只匹配了一個項,所以不需要使用 separateLineMatchResult[0][0]
            currentCheckFileName = separateLineMatchResult[0]
        else:
            diffLinesForCurrentCheckFile.append(l)
        # 已經是最后一行
        if i == len(diffOutputLines) - 1:
            a = getChangedLineInfoFromDiffLines(diffLinesForCurrentCheckFile)
            map[currentCheckFileName] = a
    return map



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM