Como ler o código de um repositório GitHub sem clonar, com gh api
Voltar para o Blog
Artigogithubdev toolshow toagente de programaçãoverboo code

Como ler o código de um repositório GitHub sem clonar, com gh api

Mafra22 de outubro de 20266 min de leitura

Desde 09/09/2026, 24 rodadas de produção deste blog usaram o gh api para consultar o GitHub, e 16 delas foram tutoriais da Verboo Code escritos lendo o repositório verbeux-ai/code sem nenhum git clone. Cada tutorial precisa de cinco a dez arquivos de um repositório com 3.115 entradas. Clonar tudo para ler dez arquivos é desperdício, e no ambiente onde a gente roda (uma VPS com sandbox de agente) nem sempre dá.

Este guia mostra os comandos do gh (GitHub CLI) que usamos para mapear, filtrar, ler e fixar a versão de um repositório só pela API. Todos foram rodados em 22/10/2026 com o gh 2.100.0. Os limites da API vêm da documentação oficial do GitHub, lida no mesmo dia.

Fluxograma em 4 passos: mapear o repositório com git/trees?recursive=1, filtrar a pasta com --jq, ler o arquivo cru com o header Accept raw, fixar a versão com ?ref; se a árvore vier truncada, descer por subárvore sem recursive
Os quatro passos, do mapa do repositório ao arquivo da versão certa, com o ramo para repositório grande demais.

Como listar todos os arquivos de um repositório GitHub sem clonar?

Com o endpoint git/trees e o parâmetro recursive. Uma chamada devolve o caminho e o tamanho de todos os arquivos do branch:

gh api "repos/verbeux-ai/code/git/trees/main?recursive=1" \
  --jq '{truncated, total: (.tree|length), arquivos: ([.tree[]|select(.type=="blob")]|length)}'

Saída em 22/10/2026:

{"arquivos":2737,"total":3115,"truncated":false}

As 3.115 entradas incluem pastas (type: "tree") e arquivos (type: "blob"). O campo que importa é truncated: se vier true, a lista está incompleta. A documentação do GitHub fixa o limite em 100.000 entradas e 7 MB por resposta recursiva. Passou disso, o caminho é pedir a árvore sem recursive e descer uma subpasta por vez, usando o sha de cada entrada tree.

Um detalhe da documentação: qualquer valor em recursive liga a recursão, inclusive 0 e false. Para desligar, omita o parâmetro.

Como ver só os arquivos de uma pasta?

Filtre a mesma árvore pelo prefixo do caminho com --jq. Assim você também vê o tamanho de cada arquivo antes de abrir:

gh api "repos/verbeux-ai/code/git/trees/main?recursive=1" \
  --jq '.tree[] | select(.type=="blob" and (.path|startswith("src/commands/add-dir/"))) | "\(.size)\t\(.path)"'
4825	src/commands/add-dir/add-dir.tsx
260	src/commands/add-dir/index.ts
3207	src/commands/add-dir/validation.ts

Para uma pasta só, o endpoint contents também lista, sem recursão:

gh api repos/verbeux-ai/code/contents/src/commands/add-dir --jq '.[] | "\(.type)\t\(.name)"'

A diferença é o teto: a documentação diz que o contents lista no máximo 1.000 arquivos por diretório e manda usar a API de árvores acima disso. Para achar arquivo pelo nome em qualquer lugar do repositório, a árvore recursiva é o caminho mais curto.

Este foi o passo que usamos para escrever o tutorial do /add-dir: a árvore mostrou os três arquivos do comando e, filtrando por outros prefixos, os arquivos de permissão e de configuração que ele toca.

Como ler o conteúdo de um arquivo pelo terminal?

Peça o arquivo ao endpoint contents com o header do formato cru. Sai o texto do arquivo, sem JSON e sem base64:

gh api repos/verbeux-ai/code/contents/src/commands/add-dir/index.ts \
  -H "Accept: application/vnd.github.raw"
import type { Command } from '../../commands.js'

const addDir = {
  type: 'local-jsx',
  name: 'add-dir',
  description: 'Add a new working directory',
  argumentHint: '<path>',
  load: () => import('./add-dir.js'),
} satisfies Command

Para achar uma linha num arquivo grande, mande a saída para o grep -n, que já devolve o número da linha:

gh api repos/verbeux-ai/code/contents/src/commands/add-dir/add-dir.tsx \
  -H "Accept: application/vnd.github.raw" | grep -n "import"

Armadilha: --jq não funciona com o formato cru

O --jq espera JSON. Com o header raw, a resposta é texto, e o gh falha com esta mensagem:

invalid character 'i' looking for beginning of value

Se você quer filtrar sem pipe (útil quando o ambiente bloqueia |, como o sandbox de alguns agentes), tire o header e decodifique o base64 dentro do próprio jq:

gh api repos/verbeux-ai/code/contents/src/commands/add-dir/add-dir.tsx \
  --jq '.content | @base64d | split("\n") | to_entries[] | select(.value|test("import")) | "\(.key+1): \(.value)"'

Isso só funciona em arquivo de até 1 MB. Acima disso o campo content vem vazio, como mostra a tabela abaixo.

Qual o limite de tamanho para ler arquivo pela API do GitHub?

Até 1 MB tudo funciona. De 1 a 100 MB, só o formato cru entrega o conteúdo. Acima de 100 MB, o endpoint não serve. Os números são da documentação oficial do endpoint de conteúdo e do de árvores:

SituaçãoO que aconteceO que fazer
Arquivo de até 1 MBTodos os formatos funcionamRaw ou --jq com @base64d
Arquivo de 1 a 100 MBcontent vem vazio e encoding vem "none"Usar Accept: application/vnd.github.raw
Arquivo acima de 100 MBEndpoint não suportadoClonar ou baixar o release
Diretório com mais de 1.000 arquivoscontents corta a listaUsar git/trees
Árvore recursiva acima de 100.000 entradas ou 7 MBtruncated: trueÁrvore sem recursive, uma subpasta por vez

No verbeux-ai/code, o maior arquivo tem 265.586 bytes, então tudo cabe na primeira linha da tabela.

Como ler o arquivo de uma versão específica?

Acrescente ?ref= com a tag, o branch ou o hash do commit. É o que garante que o tutorial descreve a versão que o leitor instalou, e não o que mudou no main depois:

gh api repos/verbeux-ai/code/releases/latest --jq .tag_name
gh api "repos/verbeux-ai/code/contents/package.json?ref=v0.15.38" \
  -H "Accept: application/vnd.github.raw" | grep -m1 '"version"'
v0.15.38
  "version": "0.15.38",

A árvore aceita o mesmo: troque main pela tag em git/trees/v0.15.38?recursive=1. E para saber quando um arquivo mudou pela última vez, o endpoint de commits filtra por caminho:

gh api "repos/verbeux-ai/code/commits?path=src/commands/add-dir/add-dir.tsx&per_page=3" \
  --jq '.[] | "\(.sha[0:7]) \(.commit.author.date[0:10])"'

Por que não usar gh search code para achar o arquivo?

Porque a busca de código tem regras de indexação que a árvore não tem, e às vezes volta vazia sem erro. No mesmo dia, a busca por um termo que existe no código voltou vazia no verbeux-ai/code e devolveu resultados no openai/codex:

gh search code "addDir" --repo verbeux-ai/code --limit 3
gh search code "useState" --repo openai/codex --limit 2 --json path --jq '.[].path'

A documentação do GitHub lista as restrições: só o branch padrão é indexado, só arquivos menores que 384 KB, só repositórios com atividade no último ano, e fork só entra se tiver mais estrelas que o original. Não sabemos qual delas pegou o nosso repositório. O ponto prático é que busca vazia não prova que o termo não existe. A árvore recursiva lista tudo, sem índice no meio.

Dá para um agente de programação fazer isso sozinho?

Dá, e é assim que os nossos tutoriais saem. O agente roda a árvore, escolhe os arquivos pelo caminho e pelo tamanho, lê cada um cru e cita o arquivo e a versão no texto. Num tutorial típico isso são de cinco a dez arquivos lidos inteiros, alguns com centenas de linhas. É aí que o custo de leitura pesa: na Verboo Code os tokens são ilimitados, então ler o arquivo inteiro para conferir uma flag custa o mesmo que ler só o trecho que você achou que bastava.

Gostou deste artigo?
Compartilhe conhecimento com sua rede.
// Leia também

Artigos relacionados