Para que o documento não fique vazio após um git checkout, observamos os bytes, não o relógio
Você já trocou de branch e o documento que estava aberto ficou em branco? Estávamos tirando capturas de tela para publicar no blog quando vimos essa cena no nosso aplicativo e, aproveitando a correção, resolvemos também um bug mais silencioso.

O mote confia nos arquivos exatamente como eles são. O conteúdo exibido na tela é igual aos bytes no disco e, ao salvar, ele também grava esses bytes sem alterações.
Mas o que acontece quando um arquivo é alterado fora do aplicativo? Se o mote não perceber, no próximo salvamento ele poderá sobrescrever o conteúdo escrito por outra pessoa.
Descobrimos esse problema enquanto tirávamos capturas de tela. Ao alternar entre branches para preparar a tela de “bytes que mudam”, o documento às vezes ficava travado em branco.
Dois problemas escondidos por trás da tela em branco
O git checkout não altera os arquivos de uma só vez. Ele apaga o arquivo existente, cria um novo e depois grava o conteúdo.
O monitor de arquivos informa esse processo por meio de vários eventos. Mas o mote lia o arquivo assim que recebia o primeiro evento. Como o conteúdo ainda não havia sido preenchido, às vezes ele lia um arquivo vazio.
Ao reler o arquivo, ele também recriava o monitor. Nesse intervalo, os eventos restantes no monitor anterior desapareciam, e a tela ficava travada em branco.
Havia também um problema mais perigoso.
Depois de salvar, o mote tratava os eventos recebidos durante 1,5 segundo como “alterações feitas por mim” e os ignorava. Mas, nesse intervalo, um formatador ou um hook de salvamento também poderia modificar o arquivo novamente.
Na prática, se o arquivo fosse alterado 0,3 segundo depois de ser salvo, o mote não mostrava nenhuma mudança. Se o usuário salvasse novamente, o conteúdo alterado externamente desaparecia silenciosamente.
Um era visível, e o outro não. A causa era a mesma.
As alterações nos arquivos estavam sendo avaliadas pelo tempo, e não pelo conteúdo.
Passamos a comparar o conteúdo em vez do tempo
Agora, quando chega um evento de arquivo, ele não é lido imediatamente. Esperamos 200ms e reiniciamos a espera sempre que chega um novo evento.
Assim, o arquivo é lido apenas uma vez, em seu estado final, depois que o processo de apagar, criar e gravar termina. Temporizadores antigos são invalidados por um número de geração. Também não criamos um temporizador que continue rodando quando nada está acontecendo.
O conteúdo lido é comparado com os últimos bytes do disco vistos pelo buffer.
Se forem iguais, significa que o aplicativo salvou o arquivo ou que o mesmo conteúdo foi gravado novamente. Se forem diferentes, trata-se de uma alteração externa real. Não importa se passaram 0,1 segundo ou 1 segundo desde o salvamento.
Ao reler o mesmo arquivo, também mantemos o monitor. Assim, os eventos não desaparecem enquanto o monitor está sendo trocado.
Só perguntamos quando há uma edição em andamento
Depois de detectar uma alteração externa, verificamos o estado do usuário.
Se houver edições não salvas, mostramos um banner. O usuário pode escolher entre recarregar o arquivo alterado ou continuar editando o conteúdo atual. Como há conteúdo que pode ser perdido em qualquer uma das opções, o aplicativo não toma essa decisão pelo usuário.
Se não houver uma edição em andamento, o novo conteúdo é carregado imediatamente. O banner não é exibido, e as posições do cursor e da rolagem são preservadas. Ao alternar entre branches enquanto se lê um documento, é mais natural manter o ponto onde a leitura parou do que mostrar uma notificação.

Também não tomamos uma decisão imediata quando o arquivo desaparece. Como outro editor pode estar renomeando o arquivo, verificamos novamente após 300ms.
Se o arquivo ainda não existir nesse momento, avisamos o usuário. O conteúdo que estava sendo escrito permanece no buffer e, ao salvar novamente, o arquivo é criado.
Verificamos seis situações no ambiente real
É difícil verificar esse problema apenas com testes unitários. Isso acontece porque ele surge quando o monitor de arquivos, o disco real e o gerenciador de janelas trabalham em conjunto.
Por isso, criamos verificações executadas em um ambiente real.
Verificamos se o buffer acompanha o arquivo mesmo depois de trocar de branch dez vezes e se uma alteração feita no arquivo 300ms após o salvamento também é refletida. Também verificamos se nenhuma notificação aparece quando o próprio aplicativo salva o arquivo e se, quando ocorre uma alteração externa durante a edição, o banner é exibido sem perder o conteúdo que estava sendo escrito.
São seis verificações ao todo. Nós as executamos a cada lançamento.

tools/e2e/external.sh em uma tela física. Todas as seis linhas mostram ok, e a última linha mostra PASS=6 FAIL=0.Tratar o arquivo como a fonte da verdade não termina em gravar exatamente o conteúdo salvo.
Quando um arquivo muda sem que saibamos, também precisamos garantir que essa alteração não passe despercebida.