O despertar da lentidão
Você está há um tempo trabalhando no seu projeto de data science. Tem uns vinte notebooks, algumas imagens, e aquela estrutura típica de pastas que parecia uma boa ideia há três meses.
Você roda git status para ver o que mexeu e… espera. E espera. E enquanto espera, dá tempo de se perguntar se o computador travou ou se está apenas meditando.
Spoiler: não está meditando. Está sofrendo.
O problema tem nome (e sobrenome)
Git não é lento. Seu repositório que é.
Quando você executa git status, o git precisa fazer duas coisas que parecem simples mas não são:
- Escanear toda a árvore de arquivos para ver o que mudou
- Comparar cada arquivo com o que tem salvo
Num repositório normal isso é instantâneo. Mas os notebooks do Jupyter são JSON disfarçado de documento. E não qualquer JSON: um que inclui código, saídas, imagens codificadas em base64, metadados do kernel, e basicamente tudo que o cara que projetou o formato pensou em enfiar.
Um notebook “pequeno” com alguns gráficos pode pesar vários megas. Multiplique isso por vinte notebooks e você tem um repositório que geme toda vez que você olha para ele.
E se ainda por cima você renomeia uma pasta… o git interpreta como “você deletou 50 arquivos e criou 50 novos”. Diversão garantida.
Solução 1: Coloque um porteiro no seu repositório
A primeira solução é tão elegante que dá raiva não ter conhecido antes.
Se chama FSMonitor e funciona assim: em vez do git escanear todo o repositório toda vez que você faz algo, o sistema operacional avisa quais arquivos mudaram.
Em outras palavras: é como ter um porteiro na entrada que te fala “só o João entrou” em vez de ter que revisar toda a lista de convidados toda vez.
Para ativar:
git config core.fsmonitor true
git config core.untrackedcache true
Pronto. É isso.
A primeira vez que você fizer git status depois de ativar vai demorar o mesmo tempo (ou mais, porque precisa inicializar o cache). Mas a partir da segunda… mágica.
No meu repositório com mais de 400 arquivos, o git status passou de 2-3 segundos para ser instantâneo. Não “rápido”. Instantâneo.
Funciona em todo lugar?
- macOS: Sim, usa FSEvents
- Linux: Sim, usa inotify (se seu kernel suporta, e suporta)
- Windows: Sim, usa ReadDirectoryChangesW
Ou seja, sim.
Solução 2: Guarde a receita, não a foto do prato
FSMonitor acelera o escaneamento, mas tem outro problema: os notebooks continuam enormes. E toda vez que você executa uma célula e salva, mesmo que o código seja o mesmo, o arquivo muda porque as saídas são diferentes.
Isso significa:
- Diffs ilegíveis (quem quer revisar base64 de uma imagem?)
- Commits inflados
- Merges do inferno
A solução se chama nbstripout e faz exatamente o que o nome indica: remove o output dos notebooks antes de fazer commit.
É como guardar a receita sem as fotos do prato pronto. O código está lá, os resultados você regenera quando quiser.
Para instalar com uv:
uv add nbstripout
uv run nbstripout --install
Ou com pip, se você é old school:
pip install nbstripout
nbstripout --install
O --install configura o git automaticamente para usar o nbstripout como filtro. A partir desse momento, quando você fizer commit de um notebook, ele é salvo sem outputs.
Para verificar que está funcionando:
git config --get filter.nbstripout.clean
Se retornar algo como nbstripout, você está no caminho certo.
E se eu precisar guardar os outputs?
Boa pergunta. Às vezes você quer fazer commit de um notebook já executado, por exemplo para documentação ou para alguém ver sem ter que executar.
O nbstripout permite marcar notebooks específicos para pular o filtro:
git -c diff.nbstripout.textconv=cat diff
Ou você pode configurar exceções no seu .gitattributes. Mas em geral, meu conselho é: não guarde outputs. Notebooks são código, não documentos finais.
Menção honrosa: git-lfs
Se além de notebooks você tem imagens ou vídeos que mudam frequentemente, existe o git-lfs (Large File Storage).
A ideia é simples: em vez de guardar o binário grande no repositório, você guarda um ponteiro e o arquivo real fica num servidor separado.
É como guardar as malas no guarda-volumes do aeroporto e levar só o comprovante.
git lfs install
git lfs track "*.png"
git lfs track "*.mp4"
Por que é só menção honrosa e não solução principal? Porque adiciona complexidade. Você precisa de um servidor LFS (GitHub e GitLab oferecem, mas têm limites), e se alguém clona o repositório sem git-lfs instalado, leva os ponteiros em vez dos arquivos.
Para notebooks, FSMonitor + nbstripout geralmente são suficientes. git-lfs é para quando você tem datasets de verdade ou assets multimídia.
O combo vencedor
Minha configuração para qualquer repositório com notebooks:
# Velocidade
git config core.fsmonitor true
git config core.untrackedcache true
# Notebooks limpos
uv add nbstripout
uv run nbstripout --install
Quatro comandos e seu repositório passa de vovô com artrite para atleta olímpico.
Verifique que tudo funciona
# FSMonitor ativo
git config --get core.fsmonitor
# Deve retornar: true
# nbstripout configurado
git config --get filter.nbstripout.clean
# Deve retornar: nbstripout
Se ambos retornarem o esperado, pronto. Aproveite seu git status instantâneo e seus diffs legíveis.
Fechamento
Na próxima vez que alguém te disser “git é lento”, você já sabe o que responder: git não é lento, seu repositório está mal configurado.
FSMonitor para que o sistema operacional faça o trabalho pesado. nbstripout para que os notebooks não pesem como se carregassem lastro.
E se depois de tudo isso ainda estiver lento… talvez seja hora de se questionar se você realmente precisa de 200 notebooks no mesmo repositório. Mas essa é outra história.
Este artigo foi escrito originalmente em espanhol e traduzido com a ajuda de IA.