Nesta página
git status
Em resumo: git status é um comando somente de leitura que inspeciona o estado atual do diretório de trabalho, da área de preparação (índice) e do histórico de commits (HEAD). Ao fazer uma comparação rápida entre esses três estados, ele informa quais arquivos não são rastreados, foram modificados ou estão preparados para o próximo commit. É a principal ferramenta para monitorar o estado do repositório antes de gravar alterações no disco.
O que o git status realmente faz?
Para dominar o Git de verdade, você precisa abandonar o modelo mental de que ele é apenas uma ferramenta que acompanha diferenças entre arquivos. Em vez disso, imagine o Git como um gerente de três árvores distintas de conteúdo. Essas árvores representam diferentes etapas do ciclo de vida do seu código:
- O diretório de trabalho (ou árvore de trabalho): o sandbox real no sistema de arquivos do seu sistema operacional. Quando você edita um arquivo no VS Code ou no Vim, modifica diretamente o diretório de trabalho.
- O índice (ou área de preparação): um arquivo de cache binário armazenado em
.git/index. Ele funciona como um manifesto pré-commit: uma listagem única e plana de diretórios que contém os caminhos exatos dos arquivos, as permissões e os hashes SHA-1 dos arquivos que formarão o próximo commit. - HEAD (o último commit): um ponteiro para o objeto de commit na ponta do seu branch atual. HEAD representa o checkpoint mais recente do seu repositório.
graph LR
subgraph "The Three Trees of Git"
A[Working Directory<br>Local Files] -->|git add| B[Index / Staging Area<br>.git/index]
B -->|git commit| C[HEAD<br>Last Commit]
end
style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#bbf,stroke:#333,stroke-width:2px
style C fill:#bfb,stroke:#333,stroke-width:2px
Quando você chama git status, o Git não faz uma varredura completa do histórico de commits. Em vez disso, executa uma diferença de três vias altamente otimizada:
- Comparação A: índice versus HEAD. O Git compara os mapeamentos de caminho e hash da área de preparação (
.git/index) com o objeto de árvore apontado porHEAD. Se um arquivo tiver um hash diferente no índice em relação a HEAD, ou existir no índice mas não em HEAD, ele será classificado como “Alterações a serem commitadas” (preparado). - Comparação B: diretório de trabalho versus índice. O Git compara os arquivos atuais no seu disco rígido com os mapeamentos de caminho e hash armazenados no índice. Se o estado de um arquivo no diretório de trabalho for diferente do registro de preparação, ele será classificado como “Alterações não preparadas para commit” (modificado).
- Comparação C: diretório de trabalho versus índice (verificação de não rastreados). Qualquer arquivo encontrado no diretório de trabalho que não tenha uma entrada correspondente no índice (e não seja ignorado pelas regras de
.gitignore) será classificado como “Arquivos não rastreados”.
O cache de estatísticas: por que git status é instantâneo
Em um projeto enorme, com centenas de milhares de arquivos, calcular o hash de cada arquivo do diretório de trabalho para compará-lo com o índice deixaria o git status extremamente lento.
Para evitar isso, o Git usa uma técnica chamada cache de estatísticas. O arquivo .git/index contém metadados de cada arquivo rastreado, incluindo:
- mtime: o horário da última modificação.
- ctime: o horário da última alteração de metadados.
- dev / ino: o dispositivo e o número do inode do sistema de arquivos.
- uid / gid: os proprietários usuário e grupo.
- tamanho do arquivo: o tamanho do arquivo em bytes.
Quando você executa git status, o Git consulta o sistema operacional para obter as estatísticas do sistema de arquivos dos arquivos do diretório de trabalho (por meio de uma chamada de sistema lstat() muito rápida). Se o tamanho do arquivo, o inode ou o horário de modificação corresponder aos valores armazenados em cache no .git/index, o Git garante que o conteúdo do arquivo não mudou. Ele deixa de ler o conteúdo e de recalcular o hash SHA-1. Só quando os metadados das estatísticas forem diferentes é que o Git abrirá o arquivo, calculará seu hash e verificará se há diferenças.
O que acontece dentro de .git/ (exploração prática)
Vamos analisar como o git status se comporta criando um repositório novo e observando como suas comparações internas de arquivos mudam a cada etapa do ciclo de vida de um arquivo.
Etapa 1: inicializar o repositório
Vamos começar inicializando um repositório limpo usando git init.
$ mkdir git-status-demo && cd git-status-demo
$ git init
Initialized empty Git repository in /git-status-demo/.git/
Se verificarmos o estado do diretório .git, veremos que ainda não há um arquivo de índice e que HEAD aponta para um branch padrão que não tem commits.
$ cat .git/HEAD
ref: refs/heads/main
$ ls -l .git/index
ls: cannot access '.git/index': No such file or directory
Se executarmos git status agora:
$ git status
On branch main
No commits yet
nothing to commit (create/copy files and use "git add" to track)
Nos bastidores: o Git verificou se existia .git/index. Como não encontrou um, concluiu que havia zero arquivos rastreados. Leu .git/HEAD para encontrar o branch atual (main), resolveu a referência do branch (que ainda não existe porque não há commits) e concluiu que não há commits.
Etapa 2: introduzir um arquivo não rastreado
Vamos criar um arquivo chamado README.md.
$ echo "# Git Status Demo" > README.md
Agora vamos verificar o git status:
$ git status
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
nothing added to commit but untracked files present (use "git add" to track)
Nos bastidores:
- O Git varre o diretório de trabalho e encontra
README.md. - Tenta ler
.git/index. O arquivo de índice ainda não existe. - Como o arquivo existe no diretório de trabalho, mas não no índice, o Git o marca como não rastreado.
Etapa 3: preparar o arquivo
Vamos preparar o arquivo usando git add.
$ git add README.md
Instantaneamente, duas coisas acontecem dentro de .git/:
- O Git compacta o conteúdo de
README.mde grava um novo objeto blob em.git/objects/. - O Git cria o arquivo
.git/index, gravando a entrada deREADME.md, incluindo suas estatísticas e o hash SHA-1 do blob.
Vamos verificar a entrada do índice usando o comando de baixo nível git ls-files --stage:
$ git ls-files --stage
100644 c5d3bc8d139371ff4cf9e97623b2255fb722b2d9 0 README.md
Vamos verificar se o blob existe em .git/objects/:
$ git cat-file -t c5d3bc8d139371ff4cf9e97623b2255fb722b2d9
blob
$ git cat-file -p c5d3bc8d139371ff4cf9e97623b2255fb722b2d9
# Git Status Demo
Agora vamos executar git status:
$ git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
Nos bastidores:
- O Git lê
.git/HEAD->refs/heads/main. A referênciarefs/heads/mainainda não existe (não há commits). - O Git lê
.git/indexe encontra uma entrada:README.mdapontando para o blobc5d3bc8d1393.... - Como
HEADestá vazio e o índice contémREADME.md, o índice tem um arquivo que não está emHEAD. Assim, o arquivo é informado como preparado para commit (arquivo novo). - O Git verifica as estatísticas do diretório de trabalho de
README.mdem comparação com as estatísticas armazenadas em cache no.git/index. Elas coincidem, portanto não há modificações não preparadas.
Etapa 4: fazer um commit
Vamos fazer o commit da alteração usando git commit.
$ git commit -m "Initial commit"
[main (root-commit) 55a420b] Initial commit
1 file changed, 1 insertion(+)
create mode 100644 README.md
Agora vamos verificar o git status:
$ git status
On branch main
nothing to commit, working tree clean
Nos bastidores:
- O commit criou um objeto de commit (hash:
55a420b...) e um objeto de árvore que representa o estado do repositório. - O Git atualizou
.git/refs/heads/mainpara conter o hash desse novo objeto de commit. - Quando o
git statusé executado, ele resolveHEAD->refs/heads/main-> commit55a420b. - Ele compara a árvore dentro do commit
55a420b(que listaREADME.mdcom o blobc5d3bc8d1393...) com o índice de preparação.git/index(que também listaREADME.mdcom o blobc5d3bc8d1393...). Os hashes são idênticos, o que significa nenhuma alteração preparada. - Ele compara as estatísticas do índice com as estatísticas do sistema de arquivos. Elas coincidem, o que significa nenhuma alteração modificada.
Etapa 5: modificar o arquivo
Vamos modificar README.md no diretório de trabalho:
$ echo "# Git Status Demo" > README.md
$ echo "Added a new line of text." >> README.md
Vamos executar git status:
$ git status
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
Nos bastidores:
- O Git chama
lstat()emREADME.mde lê seus metadados. O horário de modificação (mtime) e o tamanho do arquivo mudaram em comparação com a entrada no.git/index. - O Git abre
README.mde calcula o hash SHA-1 do conteúdo modificado (que produz um novo hash:c7cb148f2e21f06939fe9ac90d42a302294f12dd). - Como esse hash calculado é diferente do armazenado no
.git/index(c5d3bc8d1393...), o Git informa o arquivo como modificado, mas não preparado. - O Git compara a entrada do índice com a entrada da árvore de
HEAD. Ambas têmc5d3bc8d1393.... Como coincidem, não há alterações preparadas.
graph TD
subgraph "Three-Way Hash Comparison"
HEAD["HEAD Commit Tree<br>Hash: c2ba505..."]
Index["Staging Index<br>Hash: c2ba505..."]
Work["Working Directory<br>Hash: d78be55..."]
end
HEAD ===|Staged: Match| Index
Index---|Modified: Mismatch| Work
Opções detalhadas de comandos e uso avançado
Embora git status seja simples, várias opções avançadas o tornam mais poderoso para scripts, depuração e visualização de estados complexos.
1. O formato curto (--short ou -s)
Ao trabalhar com muitos arquivos modificados, a saída detalhada padrão pode ser difícil de acompanhar. O formato curto exibe as alterações em um layout compacto de duas colunas.
$ git status -s
M README.md
?? new_script.js
As colunas representam a área de preparação (coluna 1) e o diretório de trabalho (coluna 2):
M(espaço na coluna 1,Mna coluna 2): o arquivo foi modificado no diretório de trabalho, mas a modificação não está preparada.M(Mna coluna 1, espaço na coluna 2): o arquivo foi modificado e a alteração está preparada no índice.MM(nas duas colunas): o arquivo foi modificado, essas alterações foram preparadas e o arquivo foi modificado novamente no diretório de trabalho.A: o arquivo foi adicionado recentemente à área de preparação.??: o arquivo não é rastreado.
2. Incluir arquivos ignorados (--ignored)
Por padrão, os arquivos que correspondem a padrões em .gitignore ficam totalmente ocultos no status. Se você estiver investigando por que um arquivo específico não está sendo rastreado, use a flag --ignored.
$ echo "logs/" > .gitignore
$ mkdir logs && touch logs/debug.log
$ git status --ignored
On branch main
...
Ignored files:
(use "git add -f <file>..." to include in what will be committed)
logs/
3. Usar --porcelain em scripts
Se você estiver escrevendo um script de shell, um alias do git ou um script de CI/CD que precise verificar se o repositório está sujo, nunca analise a saída padrão de git status (ela pode mudar entre versões do Git). Use --porcelain.
$ git status --porcelain
M README.md
?? new_script.js
A flag --porcelain garante que o formato da saída permaneça compatível com versões anteriores e estável em todas as versões futuras do Git. Ela imprime uma saída previsível e legível por máquina, omitindo cores e textos auxiliares.
Para verificar rapidamente se um repositório tem alterações não commitadas em um script bash:
if [ -z "$(git status --porcelain)" ]; then
echo "Working directory is clean. Proceeding..."
else
echo "Error: You have uncommitted changes!" >&2
exit 1
fi
Cenário real: permissões de arquivos e finais de linha
Às vezes, git status mostra um arquivo como modificado, mas, quando você executa git diff, não vê absolutamente nenhuma alteração no código. Isso geralmente é causado por dois problemas comuns: finais de linha ou alterações no modo do arquivo.
Cenário A: permissões de arquivo (chmod)
O Git rastreia bits de execução dos arquivos (100755 para executáveis, 100644 para arquivos comuns). Se você ou um script alterar as permissões de um arquivo (por exemplo, chmod +x script.sh), o Git informará o arquivo como modificado.
Se isso acontecer em um projeto no qual as permissões dos arquivos não importam (como uma equipe multiplataforma de Windows/macOS/Linux), você pode configurar o Git para ignorar alterações de permissões:
$ git config core.filemode false
Cenário B: inconsistências nos finais de linha (LF versus CRLF)
Historicamente, os sistemas Windows usam Carriage Return + Line Feed (CRLF) para terminar linhas, enquanto Linux e macOS usam Line Feed (LF). Se um editor de texto alterar automaticamente seus finais de linha, o Git marcará o arquivo inteiro como modificado porque os hashes binários são diferentes.
Para corrigir globalmente as diferenças nos finais de linha, configure a opção autocrlf do Git:
# On Windows
$ git config --global core.autocrlf true
# On macOS/Linux
$ git config --global core.autocrlf input
Armadilhas e erros comuns
1. Executar git status em um subdiretório
Se você executar git status em um subdiretório aninhado, o Git, por padrão, mostrará os caminhos relativos a esse subdiretório, o que às vezes pode deixá-los confusos. Para ver os caminhos relativos ao diretório raiz, independentemente de onde o comando é executado, use:
$ git status --relative=false
2. Um arquivo preparado ainda aparece em “Alterações não preparadas para commit”
Este é um ponto clássico de confusão para iniciantes. Se você preparar um arquivo usando git add file.txt e depois abrir o editor e adicionar outra linha a file.txt, o git status listará o arquivo duas vezes:
Changes to be committed:
modified: file.txt
Changes not staged for commit:
modified: file.txt
Isso acontece porque o Git preparou o snapshot exato do arquivo no momento em que você executou git add. As edições posteriores existem somente no diretório de trabalho e precisam ser preparadas novamente.
3. Um arquivo em .gitignore ainda aparece
Se um arquivo já era rastreado pelo Git antes de você adicioná-lo a .gitignore, ele continuará aparecendo no git status quando for alterado. .gitignore só impede que arquivos não rastreados sejam rastreados. Para parar de rastrear o arquivo sem apagá-lo do computador, você precisa removê-lo do índice:
$ git rm --cached path/to/file.txt
Referência rápida de comandos
| Comando | Descrição |
|---|---|
git status | Mostra o status no formato completo e detalhado (padrão). |
git status -s / --short | Mostra o status em um formato condensado de duas colunas. |
git status -b / --branch | Mostra detalhes do branch e do branch rastreado (adiciona contexto ao formato curto). |
git status --ignored | Mostra os arquivos ignorados por .gitignore. |
git status --porcelain | Saída otimizada para análise por máquina e scripts. |
git status -uall | Mostra arquivos individuais dentro de diretórios não rastreados, em vez de apenas o nome do diretório. |
FAQ (perguntas frequentes)
Por que o git status diz “On branch main, nothing to commit, working tree clean”?
Essa mensagem indica que as três árvores do Git estão perfeitamente alinhadas. Os hashes SHA-1 de todos os arquivos do diretório de trabalho correspondem aos hashes listados no índice de preparação (.git/index), que por sua vez correspondem aos hashes registrados na árvore do commit HEAD. Não há modificações a fazer ou registrar.
Como o git status sabe que um arquivo foi renomeado?
O Git não rastreia renomeações explicitamente. Ele as detecta. Quando um arquivo é excluído de um caminho e adicionado em outro, o git status lê o índice e compara os hashes do conteúdo. Se o conteúdo do arquivo excluído e do arquivo adicionado for idêntico (ou muito semelhante), o Git calcula um índice de similaridade e informa o arquivo como renomeado (por exemplo, renamed: old_file.txt -> new_file.txt).
Executar git status pode alterar meus arquivos?
Não. O git status é totalmente somente leitura em relação ao seu diretório de trabalho e ao histórico de commits. Ele inspeciona arquivos e compara metadados. No máximo, pode atualizar o cache de estatísticas em .git/index para corresponder aos horários atuais do sistema de arquivos (melhorando o desempenho de comandos posteriores), mas nunca modificará seu código-fonte nem desfará alterações.
Como uso git status para verificar se estou atrás ou à frente de um branch remoto?
Se seu branch local estiver rastreando um branch remoto (por exemplo, origin/main), o git status comparará a referência HEAD do seu branch local com a referência de rastreamento remoto em cache (.git/refs/remotes/origin/main). Ele exibirá mensagens como “Your branch is ahead of ‘origin/main’ by 2 commits” ou “Your branch is behind…”. Observe que isso se baseia no seu último fetch; o Git não consulta o servidor remoto durante o git status, portanto execute git fetch primeiro para obter informações de rastreamento atuais e precisas.
Teste seus conhecimentos
Carregando quiz…