Perché git non può eseguire reimpostazioni hard / soft per percorso?


138

$ git reset -- <file_path> può resettare per percorso.

Tuttavia, $ git reset (--hard|--soft) <file_path>segnalerà un errore come di seguito:

Cannot do hard|soft reset with paths.

Risposte:


143

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.


72
Personalmente, penso che git checkout -- <path>dovrebbe essere sostituito con git reset --hard <path>. Ha molto più senso ...
vergenzt,

24
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.
Dan Fabulich,

1
@EdPlunkett Er, la seconda frase nella risposta indica quale altro comando fornisce la funzionalità.
Ambra

16
-1: il checkout a detta revisione non rimuoverà i file dalla copia di lavoro se detta revisione contiene file eliminati. reset --hardcon 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.
void.pointer

1
come indicato da @ void.pointer, il checkout non rimuove i file. Se vuoi quel comportamento, guarda questa risposta. Tuttavia, spero che un giorno arriveremo git reset --hard -- <path>. Ci sono casi d'uso legittimi per questo.
Mariusz Pawelski,

18

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 resetfunziona bene sulle sottodirectory) e non vedo alcun motivo per cui git reset --hardnon dovrebbe fare esattamente quello che stai chiedendo.


l'utilizzo di checkout mette in scena le modifiche, che non è lo stesso di un reset --soft
worc

11

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 --softnon farà nulla, in quanto è un comando per spostare la testa su HEAD (al suo stato corrente). git reset --hardd'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.


è chiaro che il ripristino ha lo scopo di spostare una testa di ramo in primo luogo, ma poiché ha la funzionalità aggiuntiva di ripristinare l'albero di lavoro e l'indice per tutti i commit e la funzionalità di ripristinare l'indice per file specifici, perché non lo fa hai la funzionalità di reimpostare l'albero di lavoro per file specifici? Credo sia quello che chiede l'OP.
Danilo Souza Morães,

Forse perché quella funzionalità (reimpostazione dell'albero di lavoro per file specifici) è già disponibile come git checkoutcomando? E fare il reset per fare la stessa cosa confonderebbe ulteriormente gli utenti. La mia risposta è stata che l' --hardopzione 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.
utente

Confrontando la prima opzione con git checkout: git reset --imposta solo l'indice, mentre git checkout --imposta solo l'albero di lavoro?
seeker_of_bacon,

4

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`

Si prega di leggere di nuovo la domanda.
Xerus il

3

C'è una ragione molto importante dietro questo: i principi di checkoutereset .

In termini Git, checkout significa "portare nell'albero di lavoro corrente". E con git checkoutpossiamo 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:

  • checkout : da qualsiasi luogo (commit indice / repo) -> albero di lavoro
  • reset : ripeti commit -> Sovrascrivi HEAD (e facoltativamente indicizza e albero di lavoro)

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 resetera 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 --hardversione, altri (ad esempio --soft) non avrebbero senso.


Mi piace questa risposta. Davvero, è 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 restoreche 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).
Mariusz Pawelski il

0

Spiegazione

Il git resetmanuale 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.

Soluzione

Se vuoi entrambi:

  • Ripristina la versione dell'indice / cache di uno o più file
  • Verifica il / i file (i) (ovvero, fai corrispondere l'albero di lavoro all'indice e esegui il commit della versione)

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: reset && check out)


-2

git reset --soft HEAD ~ 1 nome file annulla il commit ma le modifiche rimangono in locale. nome file potrebbe essere - per tutti i file sottoposti a commit


6
fataleCannot do soft reset with paths.
alt
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.