2010-03-29 5 views
41

Während reset und checkout die meiste Zeit unterschiedliche Nutzungen haben, kann ich nicht sehen, welchen Unterschied es zwischen diesen beiden gibt.Gibt es einen Unterschied zwischen "git reset --hard hash" und "git checkout hash"?

Dort ist wahrscheinlich einer oder niemand hätte gestört, eine --hard Option hinzuzufügen, etwas zu tun, das die grundlegende checkout tun kann.

Vielleicht gibt es einen Unterschied ist die Art, wie Sie die Geschichte sehen werden?

+1

ich dies Ihrer früheren Fragen zu einer meiner Antwort in einem Update abgedeckt - Blick auf die ascii Kunst in der Nähe der Spitze, vor allem, wenn es heißt "Exkurs: ..." (so sehr, wie ich mehr Repräsentant dafür würde, es hier wieder zu beantworten) – Cascabel

+0

Ich denke, dass Sie Ihre Antwort hier posten können und Rep von ihm gewinnen können. Wenn jemand nach diesem bestimmten Wissen sucht, wird er den anderen Beitrag nicht finden. Dieses eine Ziel ist ein sehr spezifisches Thema, und es verdient, seine eigene Seite zu haben. Übrigens, du scheinst mein Git-Mentor zu sein :-) harigato, senseï! –

+1

Aber ich bekomme es, der Unterschied ist, dass Reset den Zweig bewegt und nicht auscheckt. –

Antwort

52

Diese Antwort wird meist aus meiner Antwort auf eine vorherige Frage zitiert: git reset in plain english.

Die beiden sind sehr unterschiedlich. Sie führen zu demselben Status für Ihren Index und Ihren Arbeitsbaum, aber der resultierende Verlauf und der aktuelle Zweig sind nicht identisch.

Angenommen, Ihre Geschichte wie folgt aussieht, mit dem Master-Zweig zur Zeit ausgecheckt:

- A - B - C (HEAD, master) 

und Sie laufen git reset --hard B. Sie werden diese:

- A - B (HEAD, master)  # - C is still here, but there's no 
          # branch pointing to it anymore 

Sie würden tatsächlich bekommen diese Wirkung, wenn Sie --mixed oder --soft zu verwenden - der einzige Unterschied ist, was Ihre Arbeit Baum und Index geschieht. In dem --hard Fall stimmen der Arbeitsbaum und der Index B überein.

Angenommen, Sie würden stattdessen git checkout B ausführen. Du würdest das bekommen:

- A - B (HEAD) - C (master) 

Du bist in einem abgetrennten HEAD Zustand gelandet. HEAD, Arbeit Baum, Index alle übereinstimmen B, wie bei der Hard-Reset, aber der Master-Zweig wurde bei C verlassen. Wenn Sie ein neuer D an dieser Stelle begehen machen, werden Sie dieses nicht erhalten, was wahrscheinlich ist, nicht das, was Sie wollen:

- A - B - C (master) 
     \ 
     D (HEAD) 

So verwenden Sie Kasse, na ja, überprüfen, die zu begehen. Sie können damit herumspielen, tun, was Sie wollen, aber Sie haben Ihren Zweig hinter sich gelassen. Wenn Sie möchten, dass der Zweig ebenfalls verschoben wird, verwenden Sie reset.

+5

+1 wie üblich. Dieser Thread (http://marc.info/?l=git&m=120955970704567&w=2) hat auch einen Nebeneffekt hinzugefügt: Wenn Sie sich in der Mitte einer Zusammenführung befinden (zB wenn es Konflikte gibt oder nach 'git merge - -no-commit'), 'git reset --hard' vergisst etwa die Zusammenführung, aber' git checkout -f' nicht; daher würde ein 'git commit' nach dem letzteren einen Merge-Commit erzeugen, was normalerweise nicht das ist, was Sie wollen. – VonC

+0

@VonC: und wie immer ein ausgezeichneter zusätzlicher Punkt von dir! – Cascabel

14

Wenn die mit Git zur Verfügung gestellte Dokumentation nicht hilft, werfen Sie einen Blick auf A Visual Git Reference von Mark Lodato.

Insbesondere wenn Sie git checkout <non-branch> mit git reset --hard <non-branch> vergleichen (hotlinked):

git checkout master~3 http://marklodato.github.com/visual-git-guide/checkout-detached.svg.png

git reset --hard master~3 http://marklodato.github.com/visual-git-guide/reset-commit.svg.png

Beachten Sie, dass im Fall von git reset --hard master~3 Sie hinter einem Teil der DAG von Revisionen verlassen - einige Commits werden von keinem Zweig referenziert. Diese sind für (standardmäßig) 30 Tage durch reflog geschützt; Sie würden letztendlich beschnitten (entfernt) werden.

6

git-reset hash setzt die Verzweigungsreferenz auf den gegebenen Hash und prüft sie optional mit --hard.

git-checkout hash setzt den Arbeitsbaum auf den gegebenen Hash; und wenn Hash kein Name eines Zweiges ist, haben Sie am Ende einen unzusammenhängenden Kopf.

schließlich git beschäftigt sich mit 3 Dinge:

    working tree (your code) 
------------------------------------------------------------------------- 
        index/staging-area 
------------------------------------------------------------------------- 
     repository (bunch of commits, trees, branch names, etc) 

git-checkout standardmäßig aktualisiert nur den Index und die Arbeitsstruktur und kann optional etwas im Repository aktualisieren (mit -b Option)

git-reset Standardmäßig aktualisiert nur das Repository und der Index und optional die funktionierende Struktur (mit der --hard Option)

Sie können sich das Repository vorstellen dies wie:

HEAD -> master 

refs: 
    master -> sha_of_commit_X 
    dev -> sha_of_commit_Y 

objects: (addressed by sha1) 

    sha_of_commit_X, sha_of_commit_Y, sha_of_commit_Z, sha_of_commit_A .... 

git-reset manipuliert, was die Zweig Referenzen verweisen auf.

Angenommen, Ihre Geschichte sieht wie folgt aus:

  T--S--R--Q [master][dev] 
     /
    A--B--C--D--E--F--G [topic1] 
        \ 
        Z--Y--X--W [topic2][topic3] 

Beachten Sie, dass Zweige nur Namen sind, die vorher automatisch, wenn Sie zu begehen.

So haben Sie die folgenden Zweige:

master -> Q 
dev -> Q 
topic1 -> G 
topic2 -> W 
topic3 -> W 

Und Ihre aktuellen Zweig ist topic2, das heißt, die HEAD zeigt auf Thema2.

HEAD -> topic2 

Dann wird git reset X setzen Sie den Namen topic2 auf X zu zeigen; das heißt, wenn Sie ein P auf Zweig Thema2 begehen machen, wird es wie folgt aussehen:

  T--S--R--Q [master][dev] 
     /
    A--B--C--D--E--F--G [topic1] 
        \ 
        Z--Y--X--W [topic3] 
          \ 
          P [topic2]