Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Sugestão] Erro conceitual comum com relação à aplicação do comando essencial `git restore`

Em vários lugares, inclusive no vídeo dessa aula, eu já me deparei com o informação de que o comando git restore <nome do arquivo> vai restaurar esse arquivo na árvore de trabalho a partir do HEAD (último commit).

No entanto, a documentação do git deixa bem claro que a fonte (source) só será o HEAD quando a opção --staged é empregada, o que realiza a restauração do arquivo, a partir do HEAD, para o índice, conforme abaixo:

    "By default, if --staged is given, the contents are restored from HEAD, otherwise from the index. Use --source to restore from a different commit."

Dessa forma, para restaurar arquivos na árvore de trabalho a partir do HEAD, é necessário rodar o comando git restore --source <hash ou parte do hash do commit desejado, podendo ser o último> <nome do arquivo>

De forma concisa: git restore -s@ <nome do arquivo>

O que acontece é que é muito comum que o estado (versão) do arquivo que se quer restaurar na árvore de trabalho, e que está presente no último commit, é a mesma versão que ainda está no índice, visto que os arquivos passam pelo caminho árvore > índice > commit e quando se realiza o commit, o índice continua com a cópia desse arquivo (na mesma versão enviada ao commit). Então, quando se usa o comando git restore sem se passar nenhuma outra opção, o comando substitui a versão do arquivo que está na sua árvore de trabalho pela versão que está no índice, mas que, por usa vez, é a mesma versão que está no último commit. Acredito que daí vem a compreensão errônea de que o arquivo está sendo restaurado a partir da versão presente no último commit, mas não está! Está sendo restaurado a partir da versão do índice que, 'por acaso' é a mesma do último commit.

Mas, em algumas situações, as versões do índice e do HEAD podem conter diferenças, como por exemplo se você fez alguma modificação posterior ao último commit no arquivo na árvore de trabalho e o adicionou ao índice. Assim, se vc desistir dessas alterações e quiser voltar para a versão do último commit no arquivo da sua árvore de trabalho, git restore sem opções não vai funcionar. Ou você terá que restaurar a versão no índice com git restore --staged, que pegará a versão do HEAD e substituirá no índice, e depois rodar o git restore, ou rodar o git restore -s@ <nome do arquivo>.

E porque eu estou escrevendo isso tudo? Porque vi essa informação errada em muitos lugares para além desse vídeo. Até na Gemini. E essas informações que, pelo que pesquisei na documentação do Git e confirmei na prática por mim mesmo, estão erradas, me renderam dias de pesquisa mais minuciosa para entender exatamente o que o comando git restore faz.

Lembrando e resumindo: quando se quer restaurar arquivos na árvore de trabalho, o git restore, por padrão, vai pegar a versão desse mesmo arquivo logo 'acima', no índice. E quando se quer restaurar arquivos no índice, a camada logo 'acima' será o HEAD (último commit, normalmente), e é lá que será usada como fonte daquele arquivo para a restauração, que pode ser feita quando se usa a opção --staged.

Por isso mesmo que se diz que se vc fez alterações em um arquivo na sua árvore e adicionou essa versão desse arquivo no índice, para 'desfazer' essa inclusão, se roda o comando git restore --staged. Na verdade, o que acontece é que aquela versão 'nova' que vc adicionou ao índice e que vc se arrependeu, ao rodar o comando git restore --staged, essa versão 'nova' que está no índice é substituída pela versão presente no último commit.

É por isso que ao se rodar o comando git status após, será possível perceber que não existem mudanças para serem 'commitadas' com relação a esse arquivo, visto que as versões do índice e do HEAD serão idênticas. Então, git restore --staged <nome arquivo> não apaga ele do índice (para isso, se não me engano, seria o comando git rm --cached <nome arquivo>). Para confirmar que o arquivo continua no índice após o git restore --staged, basta rodar o comando git ls-files --staged. Ele não é apagado de lá.

De forma similar ao modo de funcionamento (no que tange às comparações) do git restore, o comando git status compara árvore de trabalho com o nível "imediatamente acima": o índice, e o índice e o nível "imediatamente acima": o HEAD, além de verificar arquivos novos (não rastreados).

Peço desculpas, antecipadamente, se cometi algum equívoco! Não sou nada mais que um iniciante.

Espero, sinceramente, ter contribuído.

ps. cached é sinônimo de staged.

2 respostas
solução!

Olá, Rodrigo! Tudo bem?

Primeiramente, muito obrigado por compartilhar sua observação detalhada sobre o comando git restore. É sempre ótimo ver estudantes se aprofundando na documentação e compartilhando suas descobertas.

Você está absolutamente correto ao afirmar que o comando git restore <nome do arquivo> restaura o arquivo a partir do índice (staging area) e não diretamente do HEAD, a menos que a opção --source seja especificada. A confusão geralmente ocorre porque, na prática, muitas vezes o conteúdo do índice e do HEAD são iguais, especialmente logo após um commit.

Para esclarecer:

  • git restore <nome do arquivo>: Este comando restaura o arquivo a partir do índice para a árvore de trabalho.
  • git restore --staged <nome do arquivo>: Este comando restaura o arquivo a partir do HEAD para o índice.
  • git restore --source <commit> <nome do arquivo>: Este comando restaura o arquivo a partir de um commit específico (que pode ser o HEAD) para a árvore de trabalho.

Um exemplo prático pode ajudar a ilustrar:

  1. Situação Inicial:

    • Você fez um commit (HEAD) e o índice está sincronizado com o HEAD.
    • Você modifica um arquivo (app.js) na árvore de trabalho.
  2. Comando git restore app.js:

    • Isso restaurará app.js da versão no índice para a árvore de trabalho. Se o índice ainda estiver sincronizado com o HEAD, parecerá que o arquivo foi restaurado do HEAD.
  3. Comando git restore --staged app.js:

    • Isso restaurará app.js da versão no HEAD para o índice.
  4. Comando git restore --source HEAD app.js:

    • Isso restaurará app.js da versão no HEAD para a árvore de trabalho, ignorando o índice.

Seu ponto sobre a necessidade de usar --source para restaurar diretamente do HEAD é crucial, especialmente em situações onde o índice e o HEAD divergem. Isso evita confusões e garante que você está realmente restaurando a versão desejada.

Continue mergulhando em tecnologia e se tiver dúvidas, conte com o fórum.

Abraços e bons estudos!

Prezados,

Para concluir a questão, acredito que seria essencial escrever um 'Saiba Mais' logo antes ou após as aulas nas quais se comenta, erroneamente, que o git restore restaura arquivos para a árvore de trabalho a partir do último commit explicando que na realidade esses arquivos são restaurados a partir do índice. Acho muito importante não deixar passar essa importante diferenciação conceitual.