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 --hard
com 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 reset
funciona muito bem em subdiretórios) e não vejo razão para git reset --hard
que 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 checkout
comando? E redefinir para fazer a mesma coisa confundiria ainda mais os usuários. Minha resposta foi que a --hard
opçã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 checkout
ereset
.
Em termos do Git, checkout significa "trazer para a árvore de trabalho atual". E com git checkout
isso 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 -- files
já 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 reset
ainda 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 --hard
versã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 restore
que 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 reset
manual 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
: re
set && c
heck o
ut)
git checkout -- <path>
deveria ser substituído porgit reset --hard <path>
. Faz muito mais sentido ...