Risposte:
Perché non ha senso (altri comandi forniscono già questa funzionalità) e riduce il potenziale per fare la cosa sbagliata per caso.
Un "hard reset" per un percorso è appena terminato git checkout HEAD -- <path>
(verificando la versione esistente del file).
Un ripristino software per un percorso non ha senso.
Un reset misto per un percorso è ciò che git reset -- <path>
fa.
git checkout -- <path>
non esegue un hard reset; sostituisce il contenuto dell'albero di lavoro con il contenuto messo in scena. git checkout HEAD -- <path>
esegue un hard reset per un percorso, sostituendo sia l'indice che l'albero di lavoro con la versione dal commit HEAD.
reset --hard
con un percorso fornirebbe questo pezzo mancante. Git è già così potente che la scusa "Non ti permettiamo di farlo per la tua protezione" non contiene acqua: ci sono molti modi per fare la cosa sbagliata "per caso". Niente di tutto ciò importa quando hai git reflog
.
git reset --hard -- <path>
. Ci sono casi d'uso legittimi per questo.
Puoi realizzare quello che stai cercando di fare usando git checkout HEAD <path>
.
Detto questo, il messaggio di errore fornito non ha alcun senso per me (poiché git reset
funziona bene sulle sottodirectory) e non vedo alcun motivo per cui git reset --hard
non dovrebbe fare esattamente quello che stai chiedendo.
Alla domanda su come è già stata data risposta , spiegherò il perché .
Quindi, cosa fa git reset ? A seconda dei parametri specificati, può fare due cose diverse:
Se si specifica un percorso, sostituisce i file corrispondenti nell'indice con i file di un commit (HEAD per impostazione predefinita). Questa azione non ha alcun effetto sull'albero di lavoro e viene solitamente utilizzata come opposto di git add.
Se non si specifica un percorso, sposta la testa del ramo corrente su un commit specificato e, insieme a quello , reimposta facoltativamente l'indice e l'albero di lavoro sullo stato di quel commit. Questo comportamento aggiuntivo è controllato dal parametro mode:
--soft : non toccare l'indice e l'albero di lavoro.
--mix (impostazione predefinita): reimposta l'indice ma non l'albero di lavoro.
--hard : ripristina l'indice e l'albero di lavoro.
Ci sono anche altre opzioni, consultare la documentazione per l'elenco completo e alcuni casi d'uso.
Quando non specifichi un commit, il valore predefinito è HEAD, quindi git reset --soft
non farà nulla, in quanto è un comando per spostare la testa su HEAD (al suo stato corrente). git reset --hard
d'altra parte, ha senso a causa dei suoi effetti collaterali , dice che sposta la testa su HEAD e resetta l'indice e l'albero di lavoro su HEAD.
Penso che ora dovrebbe essere chiaro il motivo per cui questa operazione non è per file specifici per sua natura - in primo luogo è destinata a spostare una testa di ramo, ripristinando l'albero di lavoro e l'indice è una funzionalità secondaria.
git checkout
comando? E fare il reset per fare la stessa cosa confonderebbe ulteriormente gli utenti. La mia risposta è stata che l' --hard
opzione non è applicabile a file specifici perché è una modalità per il ripristino del ramo, non per il ripristino dell'indice. E il ripristino dell'albero di lavoro è chiamato checkout, come puoi leggere in altre risposte. Tutto ciò è solo una cattiva progettazione dell'interfaccia utente di Git, IMHO.
git checkout
: git reset --
imposta solo l'indice, mentre git checkout --
imposta solo l'albero di lavoro?
Assicurati di inserire una barra tra origine o upstream (sorgente) e il ramo effettivo:
git reset --hard origin/branch
o
git reset --hard upstream/branch`
C'è una ragione molto importante dietro questo: i principi di checkout
ereset
.
In termini Git, checkout significa "portare nell'albero di lavoro corrente". E con git checkout
possiamo riempire l'albero di lavoro con dati provenienti da qualsiasi area, sia esso proveniente da un commit nel repository o singoli file da un commit o l' area di staging (che è anche l'impostazione predefinita).
A sua volta, git reset non ha questo ruolo. Come suggerisce il nome, ripristinerà il riferimento corrente ma avendo sempre il repository come sorgente, indipendentemente dalla "portata" (--soft, --mixed o --hard).
Ricapitolare:
Quindi ciò che può essere un po 'confuso è l'esistenza di git reset COMMIT -- files
"sovrascrivere HEAD" con solo alcuni file non ha senso!
In assenza di una spiegazione ufficiale, posso solo ipotizzare che gli sviluppatori git abbiano scoperto che reset
era ancora il nome migliore di un comando per scartare le modifiche apportate all'area di gestione temporanea e, dato che l'unica fonte di dati era il repository, quindi " estendiamo il funzionalità "invece di creare un nuovo comando.
Quindi in qualche modo git reset -- <files>
è già un po 'eccezionale: non sovrascriverà HEAD. IMHO tutte queste variazioni sarebbero eccezioni. Anche se possiamo concepire una --hard
versione, altri (ad esempio --soft
) non avrebbero senso.
git reset -- <files>
caduto come è stato aggiunto perché questa è una funzione utile ma nessuno era sicuro di quale comando dovesse essere inserito. Fortunatamente ora abbiamo molto più sano git restore
che ha funzionalità di git checkout -- <path>
git checkout <commit> -- <path>
e git reset [<commit>] -- <path>
con impostazioni predefinite molto più sane e ancora più funzioni che non si potevano fare prima (Contrariamente a quanto dice la risposta accettata. Ora puoi finalmente ripristinare facilmente solo l'albero di lavoro, senza toccare l'indice).
Il git reset
manuale elenca 3 modi di invocazione:
2 sono file-sise: non influiscono sull'albero di lavoro , ma funzionano solo sui file nell'indice specificato da <paths>
:
git reset [-q] [<tree-ish>] [--] <paths>..
git reset (--patch | -p) [<tree-ish>] [--] [<paths>...]
1 è commit-wise: funziona su tutti i file nel riferimento <commit>
e può influenzare l'albero di lavoro:
git reset [<mode>] [<commit>]
Non esiste una modalità di invocazione che opera solo su file specifici e influisce sull'albero di lavoro.
Se vuoi entrambi:
Puoi usare questo alias nel tuo file di configurazione git:
[alias]
reco = !"cd \"${GIT_PREFIX:-.}\" && git reset \"$@\" && git checkout \"$@\" && git status --short #" # Avoid: "fatal: Cannot do hard reset with paths."
È quindi possibile effettuare una delle seguenti operazioni:
$ git reco <paths>
$ git reco <branch/commit> <paths>
$ git reco -- <paths>
(Mnenonico per reco
: re
set && c
heck o
ut)
git checkout -- <path>
dovrebbe essere sostituito congit reset --hard <path>
. Ha molto più senso ...