Respostas:
Porque não faz sentido (outros comandos já fornecem essa funcionalidade) e reduz o potencial de fazer a coisa errada por acidente.
Uma "reinicialização completa" de um caminho é feita git checkout HEAD -- <path>(verificando a versão existente do arquivo).
Uma reinicialização suave de um caminho não faz sentido.
Uma redefinição mista para um caminho é o que git reset -- <path>faz.
git checkout -- <path>não faz uma reinicialização completa; ele substitui o conteúdo da árvore de trabalho pelo conteúdo preparado. git checkout HEAD -- <path>faz uma redefinição definitiva para um caminho, substituindo o índice e a árvore de trabalho pela versão do commit HEAD.
reset --hardcom um caminho forneceria essa peça que faltava. O Git já é tão poderoso que a desculpa "Não permitimos que você faça isso para sua própria proteção" mantém zero de água: existem muitas maneiras de fazer a coisa errada "por acidente". Nada disso importa quando você tem git reflog.
git reset --hard -- <path>. Existem casos de uso legítimos para isso.
Você pode realizar o que está tentando fazer usando git checkout HEAD <path>.
Dito isto, a mensagem de erro fornecida não faz sentido para mim (como git resetfunciona muito bem em subdiretórios) e não vejo razão para git reset --hardque não deva fazer exatamente o que você está pedindo.
A pergunta como já está respondida , explicarei a parte do porquê .
Então, o que o git reset faz? Dependendo dos parâmetros especificados, ele pode fazer duas coisas diferentes:
Se você especificar um caminho, ele substituirá os arquivos correspondentes no índice pelos arquivos de uma confirmação (HEAD por padrão). Essa ação não afeta a árvore de trabalho e geralmente é usada como o oposto do git add.
Se você não especificar um caminho, ele moverá o cabeçalho da ramificação atual para uma confirmação especificada e, junto com isso , redefinirá opcionalmente o índice e a árvore de trabalho para o estado dessa confirmação. Esse comportamento adicional é controlado pelo parâmetro mode:
--soft : não toque no índice e na árvore de trabalho.
--mixed (padrão): redefine o índice, mas não a árvore de trabalho.
--hard : redefine o índice e a árvore de trabalho.
Também existem outras opções, consulte a documentação para obter a lista completa e alguns casos de uso.
Quando você não especifica uma confirmação, o padrão é HEAD, portanto git reset --soft, nada fará, pois é um comando para mover a cabeça para HEAD (para seu estado atual). git reset --hard, por outro lado, faz sentido devido a seus efeitos colaterais , diz mover a cabeça para HEAD e redefinir o índice e a árvore de trabalho para HEAD.
Eu acho que agora deve estar claro por que essa operação não é para arquivos específicos por natureza - ela pretende mover uma cabeça de ramificação em primeiro lugar, redefinindo a árvore de trabalho e o índice é uma funcionalidade secundária.
git checkoutcomando? E redefinir para fazer a mesma coisa confundiria ainda mais os usuários. Minha resposta foi que a --hardopção não é aplicável a arquivos específicos porque é um modo de redefinição de ramificação, não de redefinição de índice. E a redefinição da árvore de trabalho é denominada checkout, como você pode ler em outras respostas. Tudo isso é apenas um design ruim da interface do usuário do Git, IMHO.
git checkout: git reset --define apenas o índice, enquanto git checkout --define apenas a árvore de trabalho?
Certifique-se de colocar uma barra entre a origem ou a montante (origem) e a ramificação real:
git reset --hard origin/branch
ou
git reset --hard upstream/branch`
Há uma razão muito importante por trás disso: os princípios de checkoutereset .
Em termos do Git, checkout significa "trazer para a árvore de trabalho atual". E com git checkoutisso podemos preencher a árvore de trabalho com dados de qualquer área, seja de uma confirmação no repositório ou de arquivos individuais de uma confirmação ou da área de preparação (que é o padrão).
Por sua vez, o git reset não tem essa função. Como o nome sugere, ele redefinirá a ref atual, mas sempre terá o repositório como fonte, independentemente do "alcance" (--soft, --mixed ou --hard).
Recapitular:
Portanto, o que pode ser um pouco confuso é a existência de, git reset COMMIT -- filesjá que "sobrescrever HEAD" com apenas alguns arquivos não faz sentido!
Na ausência de uma explicação oficial, posso apenas especular que os desenvolvedores do git descobriram que resetainda era o melhor nome de um comando para descartar as alterações feitas na área de preparação e, dada a única fonte de dados que era o repositório, " vamos estender o funcionalidade "em vez de criar um novo comando.
Então, de alguma forma, git reset -- <files>já é um pouco excepcional: não substitui o HEAD. IMHO todas essas variações seriam exceções. Mesmo que possamos conceber uma --hardversão, outras (por exemplo --soft) não fazem sentido.
git reset -- <files>caiu como se fosse adicionado, porque esse é um recurso útil, mas ninguém tinha certeza de qual comando deveria ser colocado. Felizmente agora temos muito mais são, git restoreque têm funcionalidade git checkout -- <path> git checkout <commit> -- <path>e git reset [<commit>] -- <path>com muitos padrões mais saudáveis e ainda mais recursos que você não poderia fazer antes (ao contrário do que a resposta aceita diz. Agora você pode finalmente restaurar facilmente apenas a árvore de trabalho, sem tocar no índice).
O git resetmanual lista três maneiras de invocação:
2 são de arquivo: Eles não afetam a árvore de trabalho , mas operam apenas nos arquivos no índice especificado por <paths>:
git reset [-q] [<tree-ish>] [--] <paths>..git reset (--patch | -p) [<tree-ish>] [--] [<paths>...]1 é de confirmação: opera em todos os arquivos no referenciado <commit>e pode afetar a árvore de trabalho:
git reset [<mode>] [<commit>]Não há modo de chamada que opera apenas em arquivos especificados e afeta a árvore de trabalho.
Se você deseja ambos:
Você pode usar esse alias no seu arquivo de configuração do git:
[alias]
reco = !"cd \"${GIT_PREFIX:-.}\" && git reset \"$@\" && git checkout \"$@\" && git status --short #" # Avoid: "fatal: Cannot do hard reset with paths."
Você pode fazer um dos seguintes:
$ git reco <paths>
$ git reco <branch/commit> <paths>
$ git reco -- <paths>
(Mnenônico para reco: reset && check out)
git checkout -- <path>deveria ser substituído porgit reset --hard <path>. Faz muito mais sentido ...