Warum kann git keine Hard / Soft-Resets nach Pfad durchführen?

137

$ git reset -- <file_path> kann über Pfad zurückgesetzt werden.

Es wird jedoch $ git reset (--hard|--soft) <file_path>ein Fehler wie folgt gemeldet:

Cannot do hard|soft reset with paths.
yao
quelle

Antworten:

142

Weil es keinen Sinn macht (andere Befehle bieten diese Funktionalität bereits an) und es das Risiko verringert, versehentlich das Falsche zu tun.

Ein "Hard Reset" für einen Pfad wird gerade durchgeführt git checkout HEAD -- <path>(Auschecken der vorhandenen Version der Datei).

Ein Soft-Reset für einen Pfad macht keinen Sinn.

Ein gemischter Reset für einen Pfad ist das, was git reset -- <path>bewirkt.

Bernstein
quelle
72
Persönlich denke ich git checkout -- <path>sollte durch ersetzt werden git reset --hard <path>. Es macht so viel mehr Sinn ...
vergenzt
24
git checkout -- <path>führt keinen Hard-Reset durch; Es ersetzt den Arbeitsbauminhalt durch den bereitgestellten Inhalt. git checkout HEAD -- <path>führt einen Hard-Reset für einen Pfad durch und ersetzt sowohl den Index als auch den Arbeitsbaum durch die Version aus dem HEAD-Commit.
Dan Fabulich
1
@EdPlunkett Er, der zweite Satz in der Antwort sagt Ihnen, welcher andere Befehl die Funktionalität bietet.
Amber
16
-1: Beim Auschecken in die Revision werden keine Dateien aus der Arbeitskopie entfernt, wenn die Revision gelöschte Dateien enthält. reset --hardmit einem Pfad würde dieses fehlende Stück liefern. Git ist bereits so mächtig, dass die Ausrede "Wir lassen Sie das nicht zu Ihrem eigenen Schutz tun" kein Wasser enthält: Es gibt viele Möglichkeiten, "aus Versehen" das Falsche zu tun. Nichts davon ist sowieso wichtig, wenn Sie haben git reflog.
void.pointer
1
Wie von @ void.pointer erwähnt, werden beim Auschecken keine Dateien entfernt. Wenn Sie dieses Verhalten möchten, schauen Sie sich diese Antwort an. Trotzdem hoffe ich, dass wir eines Tages bekommen git reset --hard -- <path>. Es gibt legitime Anwendungsfälle dafür.
Mariusz Pawelski
18

Sie können das erreichen, was Sie damit versuchen git checkout HEAD <path>.

Die bereitgestellte Fehlermeldung macht für mich jedoch keinen Sinn (da sie git resetin Unterverzeichnissen einwandfrei funktioniert), und ich sehe keinen Grund, warum Sie git reset --hardnicht genau das tun sollten, was Sie von ihr verlangen.

Aaron Kent
quelle
Mit Checkout- Phasen werden die Änderungen vorgenommen, was nicht mit einem Reset identisch ist .soft
worc
11

Die Frage wie wird schon beantwortet , ich erkläre den Warum- Teil.

Also, was macht Git Reset ? Abhängig von den angegebenen Parametern kann es zwei verschiedene Dinge tun:

  • Wenn Sie einen Pfad angeben, werden die übereinstimmenden Dateien im Index durch die Dateien aus einem Commit ersetzt (standardmäßig HEAD). Diese Aktion wirkt sich überhaupt nicht auf den Arbeitsbaum aus und wird normalerweise als Gegenteil von git add verwendet.

  • Wenn Sie keinen Pfad angeben, wird der aktuelle Verzweigungskopf in ein bestimmtes Commit verschoben und zusammen mit diesem optional der Index und der Arbeitsbaum auf den Status dieses Commits zurückgesetzt. Dieses zusätzliche Verhalten wird durch den Parameter mode gesteuert:
    --soft : Berühren Sie nicht den Index und den Arbeitsbaum.
    --mixed (Standard): Setzt den Index zurück, aber nicht den Arbeitsbaum.
    --hard : Index und Arbeitsbaum zurücksetzen.
    Es gibt auch andere Optionen. Die vollständige Liste und einige Anwendungsfälle finden Sie in der Dokumentation.

    Wenn Sie kein Commit angeben, wird standardmäßig HEAD verwendet, sodass git reset --softnichts unternommen wird, da es sich um einen Befehl handelt, den Kopf in HEAD (in den aktuellen Status) zu verschieben. git reset --hardAuf der anderen Seite ist es aufgrund seiner Nebenwirkungen sinnvoll , den Kopf auf HEAD zu bewegen und den Index und den Arbeitsbaum auf HEAD zurückzusetzen.

    Ich denke, es sollte jetzt klar sein, warum dieser Vorgang von Natur aus nicht für bestimmte Dateien gilt - er soll in erster Linie einen Verzweigungskopf verschieben, den Arbeitsbaum zurücksetzen und der Index ist eine sekundäre Funktionalität.

Benutzer
quelle
Es ist klar, dass das Zurücksetzen in erster Linie dazu gedacht ist, einen Verzweigungskopf zu verschieben. Da es jedoch die zusätzliche Funktionalität zum Zurücksetzen des Arbeitsbaums und des Index für ganze Commits und die Funktionalität zum Zurücksetzen des Index für bestimmte Dateien bietet, warum nicht? Haben Sie die Funktionalität, den Arbeitsbaum für bestimmte Dateien zurückzusetzen? Ich glaube, das ist es, was das OP verlangt.
Danilo Souza Morães
Vielleicht, weil diese Funktionalität (Zurücksetzen des Arbeitsbaums für bestimmte Dateien) bereits als git checkoutBefehl verfügbar ist ? Ein Zurücksetzen, um dasselbe zu tun, würde die Benutzer weiter verwirren. Meine Antwort war, dass diese --hardOption nicht auf bestimmte Dateien anwendbar ist, da es sich um einen Modus zum Zurücksetzen von Zweigen und nicht zum Zurücksetzen von Indizes handelt. Das Zurücksetzen des Arbeitsbaums wird als Kasse bezeichnet, wie Sie in anderen Antworten lesen können. All das ist nur ein schlechtes Design der Benutzeroberfläche von Git, IMHO.
Benutzer
Vergleich der ersten Option mit git checkout: git reset --Setzt nur den Index, während git checkout --nur der Arbeitsbaum festgelegt wird?
seeker_of_bacon
4

Stellen Sie sicher, dass Sie einen Schrägstrich zwischen Ursprung oder Upstream (Quelle) und dem tatsächlichen Zweig setzen:

git reset --hard origin/branch

oder

git reset --hard upstream/branch`
Pascal Nitcheu
quelle
Bitte lesen Sie die Frage noch einmal.
Xerus
3

Dahinter steckt ein sehr wichtiger Grund: die Prinzipien von checkoutundreset .

In Git-Begriffen bedeutet Auschecken "In den aktuellen Arbeitsbaum bringen". Und mit können git checkoutwir den Arbeitsbaum mit Daten aus jedem Bereich füllen , sei es aus einem Commit im Repository oder aus einzelnen Dateien aus einem Commit oder dem Staging-Bereich (dies ist sogar die Standardeinstellung).

Git Reset hat diese Rolle wiederum nicht. Wie der Name schon sagt, wird die aktuelle Referenz zurückgesetzt, wobei jedoch immer das Repository als Quelle verwendet wird, unabhängig von der "Reichweite" (--soft, --mixed oder --hard).

Rekapitulieren:

  • Kasse : Von überall (Index / Repo-Commit) -> Arbeitsbaum
  • Zurücksetzen : Repo-Commit -> HEAD überschreiben (und optional Index und Arbeitsbaum)

Was daher etwas verwirrend sein kann, ist die Existenz von git reset COMMIT -- files"Überschreiben von HEAD" mit nur einigen Dateien macht keinen Sinn!

In Ermangelung einer offiziellen Erklärung kann ich nur spekulieren, dass die Git-Entwickler festgestellt haben, dass dies resetimmer noch der beste Name für einen Befehl zum Verwerfen von Änderungen ist, die am Staging-Bereich vorgenommen wurden, und angesichts der einzigen Datenquelle, die das Repository war, "erweitern wir das Funktionalität "anstatt einen neuen Befehl zu erstellen.

Irgendwie git reset -- <files>ist das schon ein bisschen außergewöhnlich: Es wird den KOPF nicht überschreiben. IMHO wären alle diese Variationen Ausnahmen. Selbst wenn wir uns eine --hardVersion vorstellen können , --softwären andere (zum Beispiel ) nicht sinnvoll.

F Pereira
quelle
Ich mag diese Antwort. Wirklich, git reset -- <files>fiel wie es hinzugefügt wurde, weil dies eine nützliche Funktion ist, aber niemand war sicher, in welchen Befehl es gesetzt werden sollte. Zum Glück haben wir jetzt viel vernünftigere git restoreFunktionen mit git checkout -- <path> git checkout <commit> -- <path>und git reset [<commit>] -- <path>mit viel vernünftigeren Standardeinstellungen und noch mehr Funktionen, die Sie vorher nicht ausführen konnten (Entgegen der akzeptierten Antwort. Jetzt können Sie endlich einfach nur einen funktionierenden Baum wiederherstellen, ohne den Index zu berühren).
Mariusz Pawelski
0

Erläuterung

Das git resetHandbuch listet drei Arten des Aufrufs auf:

  • 2 sind dateiweise: Diese wirken sich nicht auf den Arbeitsbaum aus , sondern wirken sich nur auf die Dateien in dem Index aus, der durch Folgendes angegeben ist <paths>:

    • git reset [-q] [<tree-ish>] [--] <paths>..
    • git reset (--patch | -p) [<tree-ish>] [--] [<paths>...]
  • 1 ist Commit-weise: Funktioniert mit allen Dateien in der referenzierten Datei<commit> und kann sich auf den Arbeitsbaum auswirken:

    • git reset [<mode>] [<commit>]

Es gibt keinen Aufrufmodus, der nur für bestimmte Dateien gilt und sich auf den Arbeitsbaum auswirkt.

Problemumgehung

Wenn Sie beides wollen:

  • Setzen Sie die Index- / Cache-Version einer Datei zurück.
  • Überprüfen Sie die Datei (en) (dh lassen Sie den Arbeitsbaum mit dem Index und der Commit-Version übereinstimmen).

Sie können diesen Alias ​​in Ihrer Git-Konfigurationsdatei verwenden:

[alias]
  reco   = !"cd \"${GIT_PREFIX:-.}\" && git reset \"$@\" && git checkout \"$@\" && git status --short #"  # Avoid: "fatal: Cannot do hard reset with paths."

Sie können dann einen der folgenden Schritte ausführen:

$ git reco <paths>

$ git reco <branch/commit> <paths>

$ git reco -- <paths>

(Mnenonic für reco: reset && check out)

Tom Hale
quelle
-2

git reset --soft HEAD ~ 1 Dateiname macht das Commit rückgängig, aber die Änderungen bleiben lokal. Dateiname könnte sein - für alle festgeschriebenen Dateien

Peiti Li
quelle
6
tödlichCannot do soft reset with paths.
alt