Garbage Collection

Imagine a seguinte cena: você escreveu algum código e fez commit. Aí você percebe que esqueceu de rodar os testes, e você os executa, e eles mostram um erro de sintaxe. Ou você percebe um erro de digitação. Por qualquer motivo, você não tinha terminando quando achou que tinha terminado.

Antes, quando eu usava o Subversion, a única opção era adicionar a nova alteração num novo commit. Geralmente, eu acabava ficando com três ou quatro versões no meu histórico. A primeira diria "adicionar funcionalidade X", e as próximas teriam mensagens como "opa, erro de digitação" ou "correção de erro" ou "esqueci de rodar os testes".

O Git te dá outra opção: você pode incluir a nova alteração no commit anterior usando git commit --amend. Isso deixa todas as suas alterações relacionadas unidas num único commit, para que você possa entendê-lo mais rápido quando estiver revisando-o mais tarde.

Eis outro fato interessante sobre os commits do Git: o ID de um commit é um hash SHA-1 de vários pedaços de informação: o conteúdo do commit, e os IDs dos seus commits pais.

Isso significa que, quando você usa git commit --amend, você na verdade está construindo um commit completamente diferente, e apontando a referência do seu branch local para ele em vez do original. O primeiro commit que você fez ainda está lá no disco, e você ainda pode recuperá-lo (mais sobre isso depois). Entretanto, no interesse de não embaralhar a sua visualização, nem git log nem seu visualizador Git o mostrará, porque não é parte do histórico de algo [que o Git entenda] que você precise.

Em algum momento, o Git vai decidir que é hora de rodar a coleta de lixo. (Você mesmo pode iniciar este processo, usando git gc.) Iniciando de cada branch e cada tag, o Git caminha de volta pelo grafo, construindo uma lista de todos os commits que ele consegue alcançar. Depois que ele acha o fim de cada caminho, ele exclui todos os commits que não visitou.