Bare git repo — abordagem minimalista
TL;DR
Bare git repo = abordagem minimalista — só git, zero ferramentas extras.
git init --bare $HOME/.dotfilescria repo separado do working tree;--work-tree=$HOMEfaz tracking direto no home. Aliasdotfilesno shell substituigit..gitignoreé whitelist (*+!arquivoespecífico). Vantagens: nada pra instalar, máxima portabilidade. Desvantagens: sem templates, sem secrets, sem cross-OS automático.
O que é / Como funciona
Conceito básico
Um bare git repo é um repo sem working tree — contém apenas os metadados internos do git (o que normalmente vive em .git/), sem os arquivos do projeto em si. Tradicionalmente, bare repos ficam em servidores para receber git push (ex: git clone --bare).
O truque para dotfiles: criar um bare repo localmente em $HOME/.dotfiles/, mas forçar o working tree para $HOME. O resultado: o git rastreia arquivos que existem em $HOME diretamente, sem precisar de um .git/ no home.
Essa abordagem foi popularizada em 2016 num thread do Hacker News (item #11070797) e se tornou canônica pela elegância: nenhuma ferramenta extra — só git.
Setup canônico
git init --bare "$HOME/.dotfiles"
alias dotfiles='git --git-dir=$HOME/.dotfiles --work-tree=$HOME'
dotfiles config --local status.showUntrackedFiles noO que cada linha faz:
git init --bare "$HOME/.dotfiles"— cria o bare repo (só metadados git, sem working tree).alias dotfiles='...'— cria atalho que injeta--git-dire--work-treea cada comando. A partir daqui,dotfilessubstituigitpara gerenciar dotfiles.status.showUntrackedFiles no— oculta os milhares de arquivos não-rastreados em$HOMEno output dedotfiles status.
O alias deve ser persistido no ~/.zshrc (ou ~/.bashrc) para sobreviver a reinicializações:
echo "alias dotfiles='git --git-dir=\$HOME/.dotfiles --work-tree=\$HOME'" >> ~/.zshrc
source ~/.zshrcWorkflow básico
Após o setup, a operação é idêntica ao git normal — só troca git por dotfiles:
dotfiles add ~/.zshrc
dotfiles add ~/.gitconfig
dotfiles commit -m "feat: initial dotfiles"
dotfiles remote add origin git@github.com:alice/dotfiles.git
dotfiles push -u origin mainNão há passos extras de “registrar” ou “aplicar”. O que você rastreia fica disponível imediatamente no lugar certo — não há symlinks, cópias ou diretório de staging.
.gitignore whitelist
Problema: $HOME contém milhares de arquivos (downloads, caches, diretórios de apps) que não devem ser rastreados. Com o working tree em $HOME, dotfiles status listaria todo esse noise mesmo com showUntrackedFiles no.
Solução: .gitignore em $HOME configurado como whitelist — ignora tudo por default e libera só o que deve ser rastreado:
# Ignora absolutamente tudo
*
# Libera o próprio .gitignore (senão ele fica fora do repo)
!.gitignore
# Libera arquivos específicos com !
!.zshrc
!.zshenv
!.gitconfig
# Libera pastas (parents antes de children)
!.config/
!.config/nvim/
!.config/nvim/init.lua
!.config/nvim/lua/
!.config/nvim/lua/**
!.local/
!.local/bin/
!.local/bin/myscriptCombinado com status.showUntrackedFiles no, o output de dotfiles status fica limpo — só mostra o que você decidiu rastrear.
Nova máquina — checkout
Para restaurar dotfiles em uma máquina nova:
# 1. Clonar o repo como bare
git clone --bare git@github.com:alice/dotfiles.git "$HOME/.dotfiles"
# 2. Criar o alias (temporário ou já no .zshrc recém-clonado)
alias dotfiles='git --git-dir=$HOME/.dotfiles --work-tree=$HOME'
# 3. Fazer checkout — popula os arquivos em $HOME
dotfiles checkoutO passo 3 pode falhar se já existirem arquivos no home que conflitam com o repo:
error: The following untracked working tree files would be overwritten by checkout
Se isso ocorrer, há duas opções:
# Opção 1: fazer backup dos arquivos existentes e forçar checkout
mkdir -p ~/.dotfiles-backup
dotfiles checkout 2>&1 | grep -E "^\s+\." | xargs -I{} mv {} ~/.dotfiles-backup/
dotfiles checkout
# Opção 2: aceitar overwrite (só se souber que pode descartar os arquivos locais)
dotfiles checkout -fLimitações
Esta abordagem é deliberadamente minimalista. O que ela não oferece:
- Sem templates — não resolve
{{ .email }}ou variáveis por hostname/OS. Para isso, use chezmoi. - Sem secrets nativos — encryption fica externa (ex: git-crypt aplicado sobre o repo de dotfiles).
- Sem cross-OS automático — a separação por OS requer branches ou lógica condicional no próprio shell.
- Whitelist explícita exige paciência — cada novo arquivo ou pasta precisa ser liberado manualmente no
.gitignore. - Conflitos no checkout — arquivos pré-existentes no home precisam ser tratados manualmente.
showUntrackedFiles nopode esconder novos arquivos que deveriam ser versionados.
Na prática
Setup completo passo-a-passo
# 1. Inicializar o bare repo
git init --bare "$HOME/.dotfiles"
# 2. Adicionar alias ao shell e recarregar
echo "alias dotfiles='git --git-dir=\$HOME/.dotfiles --work-tree=\$HOME'" >> ~/.zshrc
source ~/.zshrc
# 3. Configurar pra ocultar untracked por default
dotfiles config --local status.showUntrackedFiles no
# 4. Adicionar primeiros dotfiles e commitar
dotfiles add ~/.zshrc
dotfiles commit -m "feat: add zshrc"
# 5. Criar a whitelist do .gitignore e commitá-la
cat > ~/.gitignore <<'EOF'
*
!.gitignore
!.zshrc
!.gitconfig
!.config/
EOF
dotfiles add ~/.gitignore
dotfiles commit -m "feat: gitignore whitelist"
# 6. Conectar ao remote e fazer o primeiro push
dotfiles remote add origin git@github.com:alice/dotfiles.git
dotfiles push -u origin mainAdicionar pasta inteira (com whitelist)
Pastas exigem que todos os diretórios parents sejam liberados antes dos filhos — o git (e o gitignore) não libera subdirs implicitamente:
# Adicionar ~/.config/nvim/ ao repo
cat >> ~/.gitignore <<'EOF'
!.config/nvim/
!.config/nvim/**
EOF
dotfiles add ~/.gitignore
dotfiles add ~/.config/nvim/
dotfiles commit -m "feat: add nvim config"O ** é necessário para incluir arquivos em subdirs profundos da pasta.
Workflow diário
O dia-a-dia é igual ao git normal:
dotfiles status # ver o que mudou
dotfiles diff # ver as diferenças
dotfiles add ~/.zshrc # adicionar mudança
dotfiles commit -m "tweak: ajuste no prompt"
dotfiles push # sincronizar pro remote
dotfiles pull # sincronizar de outra máquinaPara checar periodicamente se há novos arquivos que deveriam ser rastreados (que showUntrackedFiles no oculta):
dotfiles -c status.showUntrackedFiles=normal statusArmadilhas
(1) git status direto em $HOME lista milhares de arquivos
Causa: git status padrão em $HOME não usa o alias dotfiles — ignora a configuração de showUntrackedFiles no do repo bare.
Sintoma: terminal trava ou imprime scroll infinito de arquivos não rastreados ao rodar git status no home.
Como detectar: rodar git status diretamente em $HOME (sem alias).
Solução: nunca usar git diretamente no home para dotfiles — sempre o alias dotfiles. O git “normal” no home não tem contexto do repo bare.
(2) dotfiles status esconde arquivos novos que deveriam ser versionados
Causa: status.showUntrackedFiles no é global para o alias — oculta tudo que não está rastreado, incluindo arquivos que você esqueceu de adicionar.
Sintoma: cria ~/.config/nvim/plugin.lua, esquece de rastrear, descobre meses depois.
Como detectar: dotfiles -c status.showUntrackedFiles=normal status lista todos os untracked temporariamente.
Solução: hábito de checar untracked periodicamente; ou criar alias dotfiles-all com showUntrackedFiles=normal.
(3) Checkout em máquina nova falha por arquivo pré-existente
Causa: git se recusa a sobrescrever arquivos do home que já existem e divergem do repo — comportamento de segurança padrão.
Sintoma: mensagem error: The following untracked working tree files would be overwritten by checkout.
Como detectar: a própria mensagem de erro lista os arquivos conflitantes.
Solução: fazer backup dos arquivos existentes antes do checkout (mv ~/.zshrc ~/.dotfiles-backup/) e depois dotfiles checkout. Ou dotfiles checkout -f se souber que pode descartar as versões locais.
(4) Whitelist .gitignore com ordem errada silencia arquivos
Causa: no gitignore, !arquivo dentro de uma pasta ignorada só funciona se a pasta pai foi explicitamente liberada antes. O git não libera children de diretórios ignorados implicitamente.
Sintoma: dotfiles add ~/.config/nvim/init.lua não adiciona o arquivo — parece sumir.
Como detectar: dotfiles check-ignore -v ~/.config/nvim/init.lua mostra qual regra no .gitignore está bloqueando o path e em qual linha.
Solução: sempre liberar parents antes de children: primeiro !.config/, depois !.config/nvim/, depois !.config/nvim/init.lua. A ordem no arquivo importa.
(5) Bare repo ($HOME/.dotfiles/) rastreado por engano em outro repo
Causa: se você tem outro repo git cobrindo $HOME (ex: uma tentativa anterior com outra ferramenta), ele pode enxergar ~/.dotfiles/ como diretório não rastreado e oferecer adicioná-lo.
Sintoma: git status em outro repo mostra ~/.dotfiles/ como untracked.
Como detectar: git status no repo B lista .dotfiles/ como novo diretório.
Solução: adicionar .dotfiles/ ao .gitignore do repo B.
(6) Alias não persiste após reinicialização
Causa: o alias foi criado só na sessão atual, sem ser salvo no ~/.zshrc.
Sintoma: dotfiles: command not found ao abrir novo terminal.
Como detectar: abrir novo terminal e rodar dotfiles status.
Solução: garantir que a linha alias dotfiles='git --git-dir=$HOME/.dotfiles --work-tree=$HOME' esteja salva no ~/.zshrc (ou ~/.bashrc).
Em inglês
- bare repo — repo bare. “Git repository sem working tree — só metadados em
.git/; base da abordagem minimalista de dotfiles.” - working tree — árvore de trabalho. “Diretório onde os arquivos rastreados pelo git vivem fisicamente; forçado para
$HOMEno setup bare.” - alias — alias. “Atalho de shell (
dotfiles='git --git-dir=...') que substituigitpara operações de dotfiles.” - whitelist — whitelist / lista de permissões. “Padrão de
.gitignoreque começa com*(ignora tudo) e libera só o explícito com!arquivo.” - checkout — checkout. “Comando
dotfiles checkoutque popula os arquivos rastreados em$HOMEao restaurar numa máquina nova.” - force — forçar. “Flag
-femdotfiles checkout -fque sobrescreve arquivos existentes no home sem pedir confirmação.” - untracked — não rastreado. “Arquivo em
$HOMEque o git conhece mas que não foi explicitamente adicionado ao bare repo.” - native — nativo. “Sem dependências externas — bare repo usa apenas git, ferramenta já presente em praticamente todo sistema.”
- minimalist — minimalista. “Abordagem que resolve o problema com o mínimo possível: sem instalações, sem state files, sem configuração de ferramenta.”
- portability — portabilidade. “Capacidade de restaurar o ambiente em qualquer máquina com git disponível, sem instalar gerenciador de dotfiles.”
Veja também
- 01 - Princípios — o que são dotfiles e por que versionar — pré-req
- 04 - GNU stow — symlinks declarativos — alternativa com symlinks
- 05 - chezmoi — manager completo com templates — alternativa completa com templates e secrets
- 07 - Secrets em dotfiles — git-crypt, age, sops — secrets e arquivos sensíveis em dotfiles
- 08 - Bootstrap — máquina nova zero-to-ready — bootstrap com bare repo
- MOC do galho
- Trilha Terminal
- bare repo, whitelist
Referências
- Atlassian — Dotfiles tutorial: https://www.atlassian.com/git/tutorials/dotfiles
- HN thread original: https://news.ycombinator.com/item?id=11070797