Was ist der Unterschied zwischen git reset --mixed, --soft und --hard?

741

Ich möchte ein Commit aufteilen und bin mir nicht sicher, welche Reset-Option ich verwenden soll.

Ich habe mir die Seite angesehen . Was macht "git reset" im Klartext? , aber mir wurde klar, dass ich den Git-Index oder den Staging-Bereich nicht wirklich verstehe, und daher halfen die Erklärungen nicht.

Auch die Anwendungsfälle für --mixedund --softsehen für mich in dieser Antwort gleich aus (wenn Sie das Problem beheben und erneut festlegen möchten). Kann jemand es noch mehr kaputt machen? Mir ist klar, dass dies --mixedwahrscheinlich die Option ist, aber ich möchte wissen, warum . Und was ist mit --hard?

Kann mir jemand ein Workflow-Beispiel geben, wie die Auswahl der drei Optionen erfolgen würde?

Michael Chinen
quelle
1
Ich werde meine Antwort auf diese andere Frage bearbeiten, um sie etwas klarer zu machen.
Cascabel
Die Antwort von @mkarasek ist ziemlich gut, aber man könnte auch daran interessiert sein, sich diese Frage anzuschauen .
Brandizzi
3
Hinweis zur Selbsthilfe : Im Allgemeinen , soft: stage everything, mixed: unstage everything, hard: ignore everythingbis zu dem Commit von ich zurückzusetzen.
user1164937
Siehe auch Bob Kerns zusätzliche Kommentare dazu
ToolmakerSteve
Ein weiterer guter Artikel von David Zychmit klarer Erklärung - davidzych.com/difference-between-git-reset-soft-mixed-and-hard
src3369

Antworten:

1489

Wenn Sie eine Datei in Ihrem Repository ändern, wird die Änderung zunächst nicht bereitgestellt. Um es festzuschreiben, müssen Sie es mit bereitstellen, dh dem Index hinzufügen git add. Wenn Sie ein Commit durchführen, werden die Änderungen festgeschrieben, die dem Index hinzugefügt wurden.

git resetändert mindestens, wohin der aktuelle Zweig ( HEAD) zeigt. Der Unterschied zwischen --mixedund --softbesteht darin, ob Ihr Index ebenfalls geändert wird oder nicht. Wenn wir also mastermit dieser Reihe von Commits auf dem Ast sind :

- A - B - C (master)

HEADzeigt auf Cund der Index stimmt überein C.

Wenn wir laufen git reset --soft B, zeigt master(und damit HEAD) jetzt auf B, aber der Index hat immer noch die Änderungen von C; git statuszeigt sie als inszeniert. Wenn wir also git commitzu diesem Zeitpunkt ausgeführt werden, erhalten wir ein neues Commit mit den gleichen Änderungen wie C.


Okay, also wieder von hier aus:

- A - B - C (master)

Jetzt lass es uns tun git reset --mixed B. (Hinweis: --mixedist die Standardoption). Noch einmal masterund HEADzeigen Sie auf B, aber dieses Mal wird der Index auch so geändert, dass er übereinstimmt B. Wenn wir git commitzu diesem Zeitpunkt ausgeführt werden, geschieht nichts, da der Index übereinstimmt HEAD. Wir haben die Änderungen immer noch im Arbeitsverzeichnis, aber da sie nicht im Index enthalten sind, git statuswerden sie als nicht bereitgestellt angezeigt. Um sie zu verpflichten, würden Sie git addund dann wie gewohnt festlegen.


Und schließlich --hardist es dasselbe wie --mixed(es ändert Ihr HEADund den Index), außer dass --hardauch Ihr Arbeitsverzeichnis geändert wird . Wenn wir aktiv sind Cund ausgeführt werden git reset --hard B, werden die hinzugefügten Änderungen Csowie alle nicht festgeschriebenen Änderungen, die Sie vorgenommen haben, entfernt, und die Dateien in Ihrer Arbeitskopie stimmen mit dem Festschreiben überein B. Da Sie Änderungen auf diese Weise dauerhaft verlieren können, sollten Sie sie immer ausführen, git statusbevor Sie einen Hard-Reset durchführen, um sicherzustellen, dass Ihr Arbeitsverzeichnis sauber ist oder dass Sie Ihre nicht festgeschriebenen Änderungen verlieren können.


Und zum Schluss noch eine Visualisierung: Geben Sie hier die Bildbeschreibung ein

mkarasek
quelle
45
Mit anderen Worten, --soft verwirft das letzte Commit, --mix verwirft das letzte Commit und fügt hinzu, --hard verwirft das letzte Commit, das Hinzufügen und alle Änderungen, die Sie an den Codes vorgenommen haben, die mit git checkout HEAD
James Wang
11
@eventualEntropy Sie können alle festgeschriebenen Änderungen mit dem Reflog wiederherstellen. Nicht festgeschriebene Änderungen, mit denen entfernt wird, reset --hardsind für immer verschwunden.
Karasek
2
@ Robert Weder noch; --mixedÄndert Ihren Index, jedoch nicht Ihr Arbeitsverzeichnis, sodass lokale Änderungen davon nicht betroffen sind.
Karasek
3
Kann für visuelle Personen hilfreich sein, die Git auf einem Terminal mit Farbe verwenden: 1. 'Git Reset - Soft A' und Sie sehen B und Cs Zeug in Grün (inszeniert) 2. 'Git Reset - Mixed A' und Sie werden siehe B und Cs Zeug in rot (nicht inszeniert) 3.'git reset --hard A 'und du wirst die Änderungen von B und C nirgendwo mehr sehen (wird so sein, als ob sie nie existiert hätten)
timhc22
2
@ user1933930 1 und 3 verlassen Sie mit - A - B - C′, wobei C 'die gleichen Änderungen wie C enthält (mit unterschiedlichem Zeitstempel und möglicherweise Commit-Nachricht). 2 und 4 verlassen Sie mit - A - D, wobei D die kombinierten Änderungen von B und C enthält.
mkarasek
215

Im einfachsten Sinne:

  • --soft: Änderungen nicht festschreiben , Änderungen bleiben inszeniert ( Index ).
  • --mixed (Standard) : Änderungen aufheben + Änderungen aufheben , Änderungen bleiben im Arbeitsbaum .
  • --hard: Uncit + Unstage + Änderungen löschen , nichts mehr übrig.
Mo Ali
quelle
8
beste Antwort, weil die Antwort technische Begriffe verwendet, um eine vollständige Antwort zu liefern, die auch die prägnanteste ist
Trevor Boyd Smith
1
Wenn ich eine Datei festgeschrieben habe (nicht gepusht) und eine neu erstellte nicht verfolgte Datei habe, dann git reset --hard macht nichts? Erst wenn ich die nicht verfolgte Datei bereitstelle, wird sie aus meinem Arbeitsverzeichnis entfernt.
Michael
1
@Nikhil Kannst du erklären, wo diese Antwort falsch ist?
Ned Batchelder
1
@NedBatchelder Keiner der Punkte ist richtig: Da das Festschreiben niemals erfolgt, wenn diese Befehle verwendet werden.
Nikhil
1
@Nikhil Vielleicht meinst du damit, dass das ursprüngliche Commit noch existiert, was wahr ist. Der Zweig wurde jedoch geändert, sodass das Commit nicht mehr Teil des Zweigs ist. Sind wir uns darüber einig?
Ned Batchelder
69

Bitte beachten Sie, dass dies eine vereinfachte Erklärung ist, die als erster Schritt zum Verständnis dieser komplexen Funktionalität gedacht ist.

Kann für visuelle Lernende hilfreich sein, die nach jedem dieser Befehle visualisieren möchten, wie ihr Projektstatus aussieht:


Für diejenigen, die Terminal mit aktivierter Farbe verwenden (git config --global color.ui auto):

git reset --soft A und Sie werden B und Cs Zeug in Grün sehen (inszeniert und bereit zu begehen)

git reset --mixed A(oder git reset A) und Sie werden B und Cs Zeug in Rot sehen (nicht inszeniert und bereit, inszeniert zu werden (grün) und dann festgeschrieben)

git reset --hard A und Sie werden die Änderungen von B und C nirgendwo mehr sehen (als ob sie nie existiert hätten)


Oder für diejenigen, die ein GUI-Programm wie 'Tower' oder 'SourceTree' verwenden.

git reset --soft A und Sie werden die Inhalte von B und C im Bereich "Bereitgestellte Dateien" sehen, die zum Festschreiben bereit sind

git reset --mixed A(oder git reset A) und Sie sehen die Inhalte von B und C im Bereich "Nicht bereitgestellte Dateien", die bereit sind, in "Bereitgestellt" verschoben und dann festgeschrieben zu werden

git reset --hard A und Sie werden die Änderungen von B und C nirgendwo mehr sehen (als ob sie nie existiert hätten)

timhc22
quelle
1
Dies ist bestenfalls irreführend: Ihre Antwort lautet, als würde sich git resetnur das Aussehen der git statusAusgabe ändern .
Jub0bs
3
Ich verstehe Ihren Standpunkt, bin aber anderer Meinung, weil ich als visueller Lernender endlich verstanden habe, wie mein Projekt nach der Verwendung der drei Befehle aussah, was sie taten!
Timhc22
Ich sah es eher als eine Art „Idiot für Dummies“ an, den Leuten zu helfen, sich auf das einzulassen, was tatsächlich passiert. Können Sie sich
vorstellen,
8
Nein, wir müssen diese Antwort nicht ändern. Es bietet einen praktischen "Spickzettel". Denken Sie darüber nach: weich = grün, gemischt = rot, hart = nichts (bedeutet weg)! Wie leicht zu merken! Für diejenigen Neulinge, die nicht einmal verstehen, was diese Farben wirklich bedeuten, wissen sie zu wenig über Git, und sie werden sowieso harte Lektionen lernen, und das ist NICHT @unegmas Schuld! Übrigens, ich habe diese Antwort nur positiv bewertet, um dieser vorherigen Ablehnung entgegenzuwirken. Gute Arbeit, @unegma!
RayLuo
5
Dies diente als großartige ergänzende Zusammenfassung, um das Innenleben besser zu verstehen, wenn ich sie an anderer Stelle lese. Vielen Dank!
Spex
24

Alle anderen Antworten sind groß, aber ich finde es am besten , sie zu verstehen , indem Sie Dateien in drei Kategorien brechen: unstaged, staged, commit:

  • --hard sollte leicht zu verstehen sein, es stellt alles wieder her
  • --mixed (Standard) :
    1. unstagedDateien: nicht ändern
    2. staged Dateien: Verschieben nach unstaged
    3. commit Dateien: Verschieben nach unstaged
  • --soft::
    1. unstagedDateien: nicht ändern
    2. stagedDateien: nicht ändern
    3. commit Dateien: Verschieben nach staged

Zusammenfassend:

  • --softOption verschiebt alles (außer unstagedDateien) instaging area
  • --mixed Option verschiebt alles in unstaged area
Hansen W.
quelle
22

Hier ist eine grundlegende Erklärung für TortoiseGit-Benutzer:

git reset --softund --mixedlassen Sie Ihre Dateien unberührt.

git reset --hardÄndern Sie Ihre Dateien tatsächlich so , dass sie dem Commit entsprechen, auf das Sie zurückgesetzt haben.

In TortoiseGit ist das Konzept des Index durch die GUI sehr verborgen. Wenn Sie eine Datei ändern, müssen Sie sie nicht ausführen git add, um die Änderung dem Staging-Bereich / Index hinzuzufügen. Wenn Sie einfach Änderungen an vorhandenen Dateien vornehmen, die die Dateinamen nicht ändern git reset --softund gleich --mixedsind! Sie werden einen Unterschied nur bemerken, wenn Sie neue Dateien hinzugefügt oder Dateien umbenannt haben. In diesem Fall müssen Sie, wenn Sie git reset --mixed ausführen, Ihre Datei (en) erneut aus der Liste " Nicht versionierte Dateien" hinzufügen .

James Lawruk
quelle
Diese Antwort ist sehr unklar in Bezug auf den Unterschied zwischen weich und gemischt. und ist sogar abweisend, wenn es darum geht. Diese folgende Antwort ist klarer. stackoverflow.com/questions/2530060/…
Barlop
2
Als Benutzer von Github Desktop, der ebenfalls das gleiche Verhalten aufweist, gibt mir diese Antwort Klarheit darüber, warum ich über --mixedund verwirrt bin --soft.
Chen Li Yong
20

In diesen Fällen mag ich ein Bild, das dies hoffentlich erklären kann:

git reset --[hard/mixed/soft] ::

Geben Sie hier die Bildbeschreibung ein

Jeder Effekt hat also unterschiedliche Bereiche

  1. Schwer => WorkingDir + Index + HEAD
  2. Gemischt => Index + KOPF
  3. Soft => nur HEAD (Index und Arbeitsverzeichnis unverändert).
Tomer Ben David
quelle
15

Drei Arten von Bedauern

Viele der vorhandenen Antworten scheinen die eigentliche Frage nicht zu beantworten. Es geht darum, was die Befehle tun, nicht darum, was Sie (der Benutzer) wollen - den Anwendungsfall . Aber darum hat das OP gebeten!

Es kann hilfreicher sein, die Beschreibung dahingehend zu formulieren, was genau Sie zum Zeitpunkt der Befehlserteilung bereuengit reset . Nehmen wir an, wir haben Folgendes:

A - B - C - D <- HEAD

Hier sind einige mögliche Bedauern und was Sie dagegen tun können:

1. Ich bedauere, dass B, C und D kein einziges Commit sind.

git reset --soft A. Ich kann jetzt sofort begehen und presto, werden alle Änderungen , die seit A sind ein begehen.

2. Ich bedauere, dass B, C und D keine zehn Commits sind.

git reset --mixed A. Die Commits sind weg und der Index ist wieder bei A, aber der Arbeitsbereich sieht immer noch so aus wie nach D. Jetzt kann ich in einer ganz anderen Gruppierung hinzufügen und festschreiben.

3. Ich bedauere, dass B, C und D in diesem Zweig passiert sind . Ich wünschte, ich hätte mich nach A verzweigt und sie wären auf diesem anderen Zweig passiert.

Machen Sie einen neuen Zweig otherbranchund dann git reset --hard A. Der aktuelle Zweig endet jetzt bei A und otherbranchstammt daraus.

(Natürlich können Sie auch einen Hard-Reset verwenden, da Sie sich wünschen, B, C und D wären noch nie passiert.)

matt
quelle
5

Sie müssen sich nicht zwingen, sich an Unterschiede zwischen ihnen zu erinnern. Überlegen Sie, wie Sie tatsächlich eine Verpflichtung eingegangen sind.

1. Nehmen Sie einige Änderungen vor.

2.git hinzufügen.

3.gc -m "Ich habe etwas getan"

Mit Soft, Mixed und Hard können Sie die von Ihnen durchgeführten Operationen von 3 auf 1 aufgeben.

Soft "gab vor" nie zu sehen, dass Sie "gc -m" getan haben.

Gemischt "vorgetäuscht", nie zu sehen, dass Sie "git add" getan haben.

Schwer "vorgetäuscht", nie zu sehen, dass Sie Dateiänderungen vorgenommen haben.

qinmu2127
quelle
4

Bevor man auf diese drei Optionen eingeht, muss man drei Dinge verstehen.

1) Geschichte / KOPF

2) Stufe / Index

3) Arbeitsverzeichnis

reset --soft: Verlauf geändert, HEAD geändert, Arbeitsverzeichnis nicht geändert.

reset --mixed: Verlauf geändert, HEAD geändert, Arbeitsverzeichnis mit nicht bereitgestellten Daten geändert.

reset --hard: Verlauf geändert, HEAD geändert, Arbeitsverzeichnis wird mit verlorenen Daten geändert.

Es ist immer sicher, mit Git --soft zu gehen. Bei komplexen Anforderungen sollte eine andere Option verwendet werden.

Suresh Sharma
quelle
3

Hier gibt es eine Reihe von Antworten mit einem Missverständnis über git reset --soft. Während es einen bestimmten Zustand gibt, in dem git reset --softsich nur HEAD(ausgehend von einem Zustand mit abgenommenem Kopf) normalerweise (und für den beabsichtigten Gebrauch) etwas ändert , wird die aktuell ausgecheckte Zweigreferenz verschoben. Dies ist natürlich nicht möglich, wenn Sie keinen Zweig ausgecheckt haben (daher git reset --softändert sich nur die spezifische Bedingung HEAD).

Ich habe festgestellt, dass dies der beste Weg ist, darüber nachzudenken git reset. Sie bewegen sich nicht nur HEAD( alles macht das ), Sie bewegen auch den Zweig ref , z master. Dies ähnelt dem, was beim Ausführen passiert git commit(der aktuelle Zweig bewegt sich mit HEAD), außer dass Sie, anstatt ein neues Commit zu erstellen (und zu diesem zu wechseln), zu einem vorherigen Commit wechseln .

Dies ist der Punkt reset, an dem ein Zweig in etwas anderes als ein neues Commit geändert wird und nicht geändert wird HEAD. Sie können dies im Dokumentationsbeispiel sehen:

Machen Sie ein Commit rückgängig und machen Sie es zu einem Themenzweig

          $ git branch topic/wip     (1)
          $ git reset --hard HEAD~3  (2)
          $ git checkout topic/wip   (3)
  1. Sie haben einige Verpflichtungen eingegangen, stellen jedoch fest, dass sie verfrüht waren, um im "Master" -Zweig zu sein. Sie möchten sie in einem Themenzweig weiter polieren, erstellen Sie also einen "Topic / Wip" -Zweig aus dem aktuellen HEAD.
  2. Spulen Sie den Hauptzweig zurück, um diese drei Commits zu entfernen.
  3. Wechseln Sie zum Zweig "Thema / Löschen" und arbeiten Sie weiter.

Was ist der Sinn dieser Reihe von Befehlen? Sie möchten hier einen Zweig verschieben . masterWährend Sie masterausgecheckt haben, werden Sie ausgeführt git reset.

Die Antwort mit der höchsten Bewertung hier ist im Allgemeinen gut, aber ich dachte, ich würde dies hinzufügen, um die verschiedenen Antworten mit falschen Vorstellungen zu korrigieren.

Ändern Sie Ihren Zweig

git reset --soft <ref>: Setzt den Verzweigungszeiger für den aktuell ausgecheckten Zweig auf das Commit an der angegebenen Referenz zurück <ref>. Dateien in Ihrem Arbeitsverzeichnis und Index werden nicht geändert. Wenn Sie sich ab dieser Phase festlegen, kehren Sie direkt dorthin zurück, wo Sie vor dem git resetBefehl waren.

Ändern Sie auch Ihren Index

git reset --mixed <ref>

oder äquivalent

git reset <ref>::

Tut was --softmacht UND setzt auch den Index so zurück, dass er mit dem Commit an der angegebenen Referenz übereinstimmt. While git reset --soft HEADtut nichts (weil es heißt, dass der ausgecheckte Zweig in den ausgecheckten Zweig verschoben wird) git reset --mixed HEADoder git reset HEADist ein gleichwertiger und nützlicher Befehl, da der Index auf den Status Ihres letzten Commits zurückgesetzt wird.

Ändern Sie auch Ihr Arbeitsverzeichnis

git reset --hard <ref>: macht was --mixedmacht UND überschreibt auch Ihr Arbeitsverzeichnis. Dieser Befehl ähnelt git checkout <ref>, mit der Ausnahme, dass (und dies ist der entscheidende Punkt reset) alle Formen der git resetBewegung sind, auf die der Zweig ref HEADzeigt.

Ein Hinweis zu "so und so Befehl bewegt den KOPF":

Es ist nicht sinnvoll zu sagen, dass ein Befehl das bewegt HEAD. Jeder Befehl, der ändert, wo Sie sich in Ihrem Commit-Verlauf befinden, verschiebt den HEAD. Das ist was das HEAD ist , ein Zeiger darauf, wo immer du bist. HEADbist du und wirst dich bewegen, wann immer du es tust.

De Novo
quelle
2
"Verschieben des Zweigs ref": guter Punkt. Ich musste stackoverflow.com/a/5203843/6309 aktualisieren .
VonC
1

Eine kurze Antwort, in welchem ​​Kontext die 3 Optionen verwendet werden:

So behalten Sie die aktuellen Änderungen im Code bei, schreiben jedoch den Festschreibungsverlauf neu:

  • soft: Sie können alles auf einmal festschreiben und ein neues Festschreiben mit einer neuen Beschreibung erstellen (wenn Sie torotise git oder die meisten anderen GUIs verwenden, ist dies das zu verwendende, da Sie immer noch ankreuzen können, welche Dateien Sie im Festschreiben haben möchten, und mehrere erstellen können Commits auf diese Weise mit verschiedenen Dateien. In Sourcetree werden alle Dateien für das Commit bereitgestellt.)
  • mixed: Sie müssen die einzelnen Dateien erneut zum Index hinzufügen, bevor Sie Commits ausführen (in Sourcetree werden alle geänderten Dateien nicht bereitgestellt).

So verlieren Sie auch Ihre Änderungen im Code:

  • hard: Sie schreiben nicht nur den Verlauf neu, sondern verlieren auch alle Änderungen bis zu dem Punkt, den Sie zurückgesetzt haben
Nickpick
quelle
Ich werde in diesem Fall nicht weich und gemischt. Wenn Sie sich verpflichten müssen, was wurde dann zurückgesetzt? Übernehmen Sie die Wiederherstellung oder übernehmen Sie die Änderungen erneut (um zum ursprünglichen Zustand zurückzukehren?)
John Little
Änderungen erneut übernehmen. Es wird kein Reverse Commit geben.
Nickpick
1

Der grundlegende Unterschied zwischen verschiedenen Optionen des Befehls zum Zurücksetzen des Git ist wie folgt.

  • --soft: Setzt nur den HEAD auf das von Ihnen ausgewählte Commit zurück. Funktioniert im Grunde genauso wie das Auschecken von Git, erstellt jedoch keinen Status für getrennten Kopf.
  • --mixed (Standardoption): Setzt den HEAD auf das Commit zurück, das Sie im Verlauf ausgewählt haben, und macht die Änderungen im Index rückgängig.
  • --hard: Setzt den HEAD auf das Commit zurück, das Sie im Verlauf ausgewählt haben, macht die Änderungen im Index rückgängig und macht die Änderungen in Ihrem Arbeitsverzeichnis rückgängig.
Vishwas Abhyankar
quelle
1

--soft: Weist Git an, HEAD auf ein anderes Commit zurückzusetzen, damit der Index und das Arbeitsverzeichnis in keiner Weise geändert werden. Alle Dateien, die zwischen dem ursprünglichen HEAD und dem Commit geändert wurden, werden bereitgestellt.

--mixed: Genau wie beim Soft wird dadurch HEAD auf ein anderes Commit zurückgesetzt. Außerdem wird der Index zurückgesetzt, damit er mit ihm übereinstimmt, während das Arbeitsverzeichnis nicht berührt wird. Alle Änderungen bleiben im Arbeitsverzeichnis und werden als geändert angezeigt, jedoch nicht bereitgestellt.

--hard: Dies setzt alles zurück - es setzt HEAD auf ein anderes Commit zurück, setzt den Index zurück, um mit ihm übereinzustimmen, und setzt das Arbeitsverzeichnis zurück, um ebenfalls mit ihm übereinzustimmen.

Der Hauptunterschied zwischen --mixedund --softbesteht darin, ob Ihr Index ebenfalls geändert wird oder nicht. Weitere Informationen hierzu finden Sie hier .

Nesha Zoric
quelle
0

mkaraseks Antwort ist großartig, in einfachen Worten können wir sagen ...

  • git reset --soft: Setzen Sie das HEADauf das beabsichtigte Commit, aber behalten Sie Ihre Änderungen aus den letzten Commits bei
  • git reset --mixed: Es ist dasselbe wie, git reset --softaber der einzige Unterschied besteht darin, dass Ihre Änderungen gegenüber den letzten Commits nicht mehr vorgenommen werden
  • git reset --hard: Setzen Sie Ihre Option HEADauf das von Ihnen angegebene Commit und setzen Sie alle Änderungen aus den letzten Commits zurück, einschließlich nicht festgeschriebener Änderungen.
Vivek Maru
quelle