Construindo Gitnarrative: Como eu analiso a história do Git com Python para extrair padrões de desenvolvimento

Quando comecei a construir o Gitnarrative, pensei que a parte mais difícil seria a integração da IA. Acontece que o verdadeiro desafio foi analisar os repositórios Git de uma maneira que realmente captura padrões significativos de desenvolvimento. Veja como eu construí o mecanismo de análise Git que alimenta a geração de histórias de Gitnarrative. O desafio: entender a história bagunçada que todo repositório Git conta uma história, mas extrair essa história programaticamente é complexa. Considere essas mensagens reais de confirmação de um projeto típico: “corrigir bug” “refactor” “Atualizar dependências” “Isso finalmente funciona” “reverter o último commit” “realmente corrige o bug desta vez” Digite o modo de tela cheia do modo de tela cheia. Escolha da biblioteca: pygit2 vs gitpython Eu avaliei as duas principais bibliotecas do Python Git: gitpython: mais pitônico e mais fácil de usar o importação repo git = git.repo (‘/path/to/repo’) COMTIMS = list (repo.iter_commits ()) inserir melhor, o modo completo ‘). pygit2.repository (‘/path/to/repo’) walker = repo.walk (repo.head.target) Digite o modo de saída da tela cheia de tela cheia, escolhi o Pygit2 porque as necessidades gitnarrativas para processar repositórios com milhares de combate com eficiência. A diferença de desempenho é significativa para grandes repositórios. Arquitetura de análise do núcleo Aqui está a base do meu mecanismo de análise Git: a partir de dataclasses importar dataclass do dateTime importa datetime da lista de importação de digitação, dita, defina importar pygit2 @dataclass.[str]
Adições: Int Deleções: Int Autor: STR IS_MERGE: BOOL Complexity_Score: Float Commit_Type: STR # ‘Recurso’, ‘Bugfix’, ‘RefActor’, ‘Docs’, etc. Classe Gitanalyzer: Def __init __ (Repo_Phather: STR): Self.repo = Pygit2.re -> dict: Commits = self._extract_Commits () padrões = self._identify_patterns (COMITA) TIMINA = Self._build_timeline (Commits) Milestones = self._detect_milestones (Cometm) Return {“Commits”: Commits, “Patterns”: Patterns “Timely” Timely “Timely” Timeline “Timeline (Timeline (Timeline (Comets): Return {” Commits “: Commits,” Patterns “: Patterns” Timely “Timely” Timeline “” Timeline (Timeline (Timeline (Comets): “Commily”: Self._Generate_summary (Cometida, padrões)} Digite o modo de tela cheia de saída de protuberância de tela cheia Reconhecimento de padrões: o coração da extração da história O principal insight é que os padrões de comprometimento revelam fases de desenvolvimento. Veja como eu os identifico: 1. Classificação do tipo de comprometimento def _classify_comit (self, commit_message: str, files_changed: list[str]) -> str: message_lower = commit_message.lower () # corrigir padrões se houver (palavra -chave em message_lower para palavra -chave em [‘fix’, ‘bug’, ‘issue’, ‘error’]): Retorne ‘Bugfix’ # Padrões de recurso Se houver (palavra -chave em message_lower para palavra -chave em [‘add’, ‘implement’, ‘create’, ‘feature’]): Retornar ‘Recurso’ # Padrões de refactor Se houver (palavra -chave em message_lower para palavra -chave em [‘refactor’, ‘restructure’, ‘reorganize’]): Retorne ‘Refactor’ # documentação se houver (palavra -chave em message_lower para palavra -chave em [‘doc’, ‘readme’, ‘comment’]): Retornar ‘Docs’ # dependência/configuração alterações se houver (file.endswith ((‘.[CommitAnalysis]) -> Lista[Dict]: fases = []
current_phase = nenhum para i, comprometido em enumerado (cometidos): # Procure indicadores de transição de fase se self._is_architecture_change (commit): se current_phase: phases.append (current_phase) current_phase = {‘type’: ‘arquitetura_change’, ‘start_commit’: Commit.ShaSe = {‘type’: ‘ [commit]
} elif self._is_feature_burst (COMPRIMENTO[max(0, i-5):i+1]): # Recurso múltiplo se compromete em curto período de tempo, se não current_phase ou current_phase[‘type’] ! = ‘característica_development’: se current_phase: phases.append (current_phase) current_phase = {‘type’: ‘festere_development’, ‘start_comit’: commit.sha, ‘description’: ‘Rapid Feature Development Fase’, Commits ‘: [commit]
} se current_phase: current_phase[‘commits’].Append (Commit) Fases de retorno def _is_architecture_change (self, Commit: CommiteRanalysis) -> bool: # alta contagem de alterações de arquivos + padrões específicos retornar (len (commit.files_changed)> 10 e commit.complexity_score> 0.8 e qualquer palavra -chave em commit.message.lower () para chave [‘refactor’, ‘restructure’, ‘migrate’])) Digite o modo de saída de tela cheia Modo de tela cheia 3. Detecção de luta e inovação é aqui que acontece a mágica de contar histórias: def _detect_truggle_patterns (self, comete: list[CommitAnalysis]) -> Lista[Dict]: lutas = []

para i no intervalo (len (commits) – 3): janela = começos[i:i+4]

# Procure várias tentativas para a mesma questão se self._is_truggle_sequence (Window): lutas.append ({‘type’: ‘Debugging_truggle’, ‘Commits’: Window, ‘Descrição’: Self._Describe_truggle (Window), ‘Resolução_Commit’: Self._Find_Resolic[i+4:i+10])}) Retorne lutas def _is_truggle_sequence (self, cometa: list[CommitAnalysis]) -> BOOL: # Múltiplas tentativas de correção de bugs em curto período de tempo bugfix_count = soma (1 para C em Commits se c.Commit_Type == ‘Bugfix’) # cluster de tempo (todos alguns dias de si) time_span = (Cometidos[-1].Timestamp – COMITES[0].timestamp). <= 3

def _find_resolution(self, following_commits: List[CommitAnalysis]) -> CommitsAlysisis: # Procure o comprometimento que provavelmente resolveu o problema para comprometer em seguidores_commits: if (‘work’ em commit.message.lower () ou ‘corrigir’ em commit.message.lower () ou commit.compplexity_score> 0.6): retorno de retorno nenhum retorno de tela cheia de tela de tela completa. CONMITIÇÕES: Lista[CommitAnalysis]) -> dict: # o grupo se compromete com períodos de tempo mensal_activity = defaultDict (list) para comprometimento em commit: mensly_key = commit.timestamp.strftime (‘%y -%m’) mensal_activity_activity[month_key].Append (Commit) Timeline = {} para o mês, Month_Commits em Monthly_Activity.items (): Linha do tempo[month] = {‘Total_Commits’: len (me mês_commits), ‘commit_types’: self._analyze_commit_distribution (me mês_commits), ‘major_changes’: self._identify_major_changes (me mês_commits), ‘Mensev_velocity’ :__cal _calculate_velocity (self, cometa: lista[CommitAnalysis]) -> Float: Se não for cometido: retorne o fator 0,0 # na frequência de comprometimento, complexidade e alterações de arquivo total_complexity = soma (c.complexity_score para c em commits) total_files = soma (len (c.files_changed) para c in cometidos) retorna (total_complexity * out -len) / len (len) para c para os cometidos) retorna (total_comrelexity * outfiles) / len (len) (len) para C para os cometidos). exigiu com eficiência várias otimizações: 1. Lazy Loading def _extract_Commits (self, max_commits: int = 1000) -> Lista[CommitAnalysis]: # O processo se compromete em lotes para evitar problemas de memória walker = self.repo.walk (self.repo.head.target) Commits = []

para i, comprometê -lo em enumerar (walker): se i> = max_commits: break Commits.append (self._analyze_single_commit (commit)) return Cometits Enter Modo FullScreen Sair @lRu_cache (manssmE sha: str) -> Float: # cache de cache caro cache por commit compromet = self.repo[sha]
# … Cálculo da complexidade A pontuação do retorno da tela Full -Screen Sair[str]) -> Lista[Dict]: com processpoolExecutor () como executor: loop = asyncio.get_event_loop () tarefas = [
loop.run_in_executor(executor, analyze_single_repo, path)
for path in repo_paths
]
Retorno aguarda asyncio.gather (*tarefas) Digite o modo de tela cheia Sair da tela cheia Integração do modo com a geração de histórias da IA ​​que a saída de análise se alimenta diretamente nos avisos da IA: DEF format_for_ai_prompt (self, análise: dict) -> str: prompt_data = {‘repositório_summary’: análise) ->[‘summary’]’Development_phases’: Análise[‘patterns’][‘phases’]’key_strugles’: análise[‘patterns’][‘struggles’]’Breakthrough_moments’: Análise[‘milestones’]’Linha do tempo’: análise[‘timeline’]
} return self._build_narrative_prompt (prompt_data) Digite o modo de tela cheia de tela cheia desafios e soluções Desafio 1: Repositórios com composição inconsistente Mensagem Ressolution: Matriz de padrões com múltiplas estratégias de falência e análise baseada em arquivos 2: Merge Commissões Criando ruído na repercussão: a estratégia de filtragem que focaliza com base em que se concentra com base em que a estratégia de focos sobre a base de repercussão sobre a base de repercussão e a estratégia de focos sobre a base de repercussão e a estratégia de focos sobre a focagem de focos sobre a base de repercussão e a estratégia de focos sobre a focagem de que se refogam. Compromits) Solução: Estratégia de amostragem que captura o representante de diferentes períodos de tempo e validação O mecanismo de análise processa com sucesso repositórios que variam de pequenos projetos pessoais a grandes bases de código de código aberto. Quando testado no repositório do React, ele identificou corretamente: a fase experimental inicial (2013) Reescritas principais de arquitetura (fibra, ganchos) Períodos de otimização de desempenho Fases de estabilização da API O que é o próximo melhorias atuais no desenvolvimento: o melhor processamento de idioma natural da MONIMESTO MENSAGEM MODELEMENT MODELATIONFICATIONATIFICATION com o problema de rastrear o suporte para o apoio ao contexto de gestoooPO MonthoePo Models Modelos para a classificação da GETATIONADORA com o suporte de dados para o contexto mais rico para o apoio à MonthoePO, a MonthoePO, com o apoio de mecanismo, a base de modelos para a classificação de questões com o suporte ao contexto mais rico para o apoio de gestão, o MontOorePo. Ao extrair padrões significativos da história, podemos transformar logs Git chatos em narrativas convincentes sobre o desenvolvimento de software. O Gitnarrative está disponível em – Experimente com seus próprios repositórios para ver esses padrões em ação. Que padrões você notou em sua própria história do Git? Eu adoraria ouvir sobre padrões de compromisso interessantes que você descobriu em seus projetos.

Fonte

Você pode ter perdido