Quem Mudou

Atribui o código à pessoa, ticket, branch e pull request que o produziu, usando apenas o histórico local do git. Útil sempre que o usuário perguntar quem escreveu, alterou, adicionou, tocou ou é dono de algum código.

O que é Quem Mudou?

Este skill (ferramenta) para agentes de IA como Claude Code responde à pergunta "quem escreveu/funcionalidade/ticket/linha" sem sair do terminal, usando apenas o histórico git local. Ele analisa um arquivo, intervalo de linhas ou função e retorna nome do autor, hash do commit, número do ticket, branch, data, número do PR e links clicáveis para o commit e PR. Suporta os principais hosts de código (Bitbucket, GitHub, GitLab) e modos de operação: arquivo completo (top contribuidores + últimos 12 commits), intervalo de linhas (atribuição por linha) e modo `raw` para verdade byte a byte. O skill resolve nomes de função para intervalos de linha, aplica heurísticas de confiança (squash, PR não mesclado, ticket faltando) e nunca inventa informações — respeitando regras de honestidade. Ideal para desenvolvedores que precisam de rastreabilidade rápida de código sem depender de APIs externas.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Daniyal12333/claude-code-skills/tree/HEAD/who-changed

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que Quem Mudou faz?

Responda "quem construiu isso, sob qual ticket e quando" sem sair do terminal. Tudo o que é necessário já está no histórico git local. A única coisa que o host de código adiciona é a narrativa do PR, e a saída fornece um link para isso.

Ele substitui um loop manual: abrir o arquivo, encontrar a funcionalidade, abrir a visualização de blame, copiar um hash, colá-lo no host de código, navegar até o PR, ler o ticket e o autor.

O que o usuário recebe

Nome do autor, hash do commit, número do ticket, nome da branch, data, número do PR e links clicáveis para o commit e PR. Um veredito principal para o intervalo e, em seguida, uma tabela de cada commit que tocou no código.

Executar o script

bash ~/.claude/skills/who-changed/scripts/who-changed.sh <arquivo> [início fim] [raw]

Se o skill estiver instalado por projeto, o caminho é .claude/skills/who-changed/scripts/who-changed.sh.

  • <arquivo> sozinho: modo arquivo completo. Principais contribuidores mais os últimos 12 commits.
  • <arquivo> <início> <fim> (ou um número de linha): modo intervalo de linhas. Propriedade de linhas por commit.
  • Anexar raw: blame sem -w -C -M, para quando o usuário quiser a verdade byte a byte.

Sobrescritas de ambiente: WHO_CHANGED_BASE define a referência para a qual a busca de PR caminha (padrão: origin/HEAD, depois origin/main, origin/master, main, master); WHO_CHANGED_TICKET_REGEX altera o padrão do ticket (padrão [A-Z][A-Z0-9]+-[0-9]+).

O script imprime um relatório separado por tabulações e nunca escreve no repositório ou na rede. Reformate-o para o usuário — não cole o TSV bruto.

Etapa 1: resolver o alvo para um intervalo de linhas

O script aceita números, então um nome de função precisa ser transformado em um intervalo primeiro. O atalho -L :nomeDaFunção: do Git depende de um padrão de função específico da linguagem e, para muitas linguagens (membros de classe TypeScript em particular), falha com no match. Resolva o intervalo você mesmo:

  1. Pesquise (grep) pela declaração, por exemplo ^\s*(public|private|protected)?\s*(async\s+)?<nome>\s*[(<], e <nome>\s*[:=]\s*(function|\() para propriedades de arrow function. Para HTML ou CSS, pesquise pelo seletor, chave ou bloco literal.
  2. Leia a partir dessa linha e faça a correspondência de chaves a partir do primeiro { para encontrar a linha de fechamento.
  3. Se o nome corresponder em mais de um lugar, liste as correspondências e pergunte qual delas. Nunca escolha silenciosamente a primeira — nomes comuns frequentemente existem em vários arquivos.

Os números de linha vêm da árvore de trabalho, então eles se alinham com o que o usuário vê em seu editor.

Dado um intervalo explícito (285-300, 285, L285-L300), use-o como está. Dado apenas um caminho de arquivo, use o modo arquivo completo.

Etapa 2: ler a saída

O bloco ## meta carrega base (a referência para a qual a busca de PR caminha), base_tip_date, web e host (base do link, derivada de git remote), o modo de blame e se o arquivo tem alterações não commitadas.

As linhas em ## commits são ordenadas por linhas possuídas. O veredito é a primeira linha — o commit que possui a maior parte do intervalo. Mencione o segundo colocado quando o intervalo for genuinamente compartilhado; uma função construída por quatro pessoas ao longo de três anos não deve ser reportada como pertencendo a uma.

O script já constrói commit_url e pr_url para remotos Bitbucket, GitHub e GitLab. Quando eles são -, não há remoto reconhecível — diga isso e omita os links em vez de inventar um host.

Apresente assim (os nomes abaixo são inventados):

### calculateTotal - src/cart/cart.service.ts:42-61

**Alice Moreno** · `a1b2c3d` · 2023-02-08 · possui 13 de 20 linhas
Ticket SHOP-88 · branch `SHOP-88-cart-totals` · PR #41

| Linhas | Autor | Commit | Data | Ticket | Branch | PR |
|---|---|---|---|---|---|---|
| 13 | Alice Moreno | a1b2c3d | 2023-02-08 | SHOP-88 | SHOP-88-cart-totals | #41 |
| 6 | Ben Carter | 9f8e7d6 | 2026-03-11 | SHOP-310 | SHOP-310-rounding-fix | não mesclado |
| 1 | Chen Wei | 4c5d6e7 | 2024-06-20 | — | release-2024-06 | #112 |

Em seguida, os links e, em seguida, uma linha de ressalva sempre que uma bandeira de confiança for acionada.

Rótulos de confiança e o que dizer sobre cada um

RótuloSignificadoDiga ao usuário
okBranch de ticket mesclada via um PRNada necessário
local-onlyCommit não está em base ainda"Ainda não mesclado à branch base" — não há PR
no-pr-mergeNa linha principal, mas nenhuma mesclagem de PR o carregaCommitado diretamente na linha principal, ou o assunto da mesclagem quebrou a convenção
squashNúmero do PR lido de um sufixo (#123)Mesclado via squash, então o histórico por linha dentro daquele PR é achatado
low-no-ticketNenhum ticket na mensagem ou na branchInforme que nenhum ticket foi registrado. Não adivinhe um
low-integration-branchMesclado via uma branch sem ticket no nomeO PR é onde a branch de integração pousou, não onde o código foi escrito. Confiança baixa
uncommittedNot Committed YetEdições locais não commitadas; excluídas do veredito

Código mais antigo frequentemente chega através de branches de integração de longa duração (develop, release-*, ui-dev). Para esses, a resposta honesta é "mesclado à linha principal via PR #112, mas aquele PR é uma branch de integração — não é o PR no qual isso foi escrito."

Por que -w -C -M é o padrão

-w ignora espaços em branco, -M segue linhas movidas dentro do arquivo, -C segue linhas copiadas de outro arquivo. Isso não é cosmético. Pegue um bloco escrito em 2023 e apenas re-indentado em 2026 (números ilustrativos):

  • inteligente (-w -C -M): 9 de 9 linhas vão para o autor original, 2023 — correto
  • bruto: 8 de 9 linhas vão para a pessoa que re-indentou, 2026 — credita a pessoa com código antigo

Portanto, o autor nomeado é a última pessoa a mudar o comportamento, não a última a tocar em bytes. Diga isso quando for importante e ofereça raw como acompanhamento.

Regras de honestidade

  • Nunca invente um ID de ticket. Nenhum ticket na mensagem do commit ou na branch: relate — e diga que nenhum ticket foi registrado.
  • Nunca invente um autor. Se o blame for inconclusivo, diga quais commits são candidatos.
  • Distinga "mesclado via" de "escrito em" sempre que uma bandeira de baixa confiança for acionada.
  • Se base_tip_date parecer desatualizado, observe que a referência base não foi buscada recentemente e que mesclagens recentes podem ser perdidas. Sugira git fetch origin — não execute sem permissão.

Limites que valem a pena mencionar quando relevante

  • O "porquê" não está no git. A descrição do PR, revisores e título do ticket precisam da API e credenciais do host de código ou rastreador. O link do PR é o ponto de entrega.
  • Mesclagens squash achatam o histórico. Se um PR foi squashado, um commit possui toda a funcionalidade e a atribuição por linha dentro dela se perde.
  • --ancestry-path escolhe a primeira mesclagem que levou o commit à linha principal. Com branches de funcionalidade aninhadas, isso pode ser uma mesclagem intermediária, não o PR do próprio ticket.
  • Contribuidores de arquivo completo não seguem renomeações. git shortlog não tem --follow; a lista de commits segue renomeações, o total de contribuidores não.
  • -C ocasionalmente surpreende ao atribuir código copiado e colado ao arquivo de onde veio.
  • A detecção de PR reconhece três estilos de mensagem de mesclagem: Bitbucket (Merged in <branch> (pull request #N)), GitHub (Merge pull request #N from ...), e squash (... (#N)). Outros estilos caem em no-pr-merge.

Fallback se o script não estiver disponível

git blame -w -C -M -L <início>,<fim> --date=short -- <arquivo>
git log -1 --date=short --pretty=format:"%H%n%an%n%ad%n%s%n%b" <sha>
git merge-base --is-ancestor <sha> origin/main     # não é ancestral -> não mesclado
git log --merges --ancestry-path --reverse --pretty=format:"%h|%s" <sha>..origin/main | grep -m1 "pull request"
git branch --contains <sha>                        # caso não mesclado

Analise o assunto da mesclagem para a branch e número do PR. Duas armadilhas: git shortlog precisa de um HEAD explícito ou lê silenciosamente da entrada padrão e retorna nada, e nomes de branch podem ser prefixados (feature/SHOP-88-...), então não ancore a regex do ticket ao início da string.

Habilidades Relacionadas