What's the difference between git reset --mixed, --soft, and --hard?

后端 未结 15 1143
野的像风
野的像风 2020-11-22 14:39

I\'m looking to split a commit up and not sure which reset option to use.

I was looking at the page In plain English, what does "git reset" do?, but I real

相关标签:
15条回答
  • 2020-11-22 15:14

    Three types of regret

    A lot of the existing answers don't seem to answer the actual question. They are about what the commands do, not about what you (the user) want — the use case. But that is what the OP asked about!

    It might be more helpful to couch the description in terms of what it is precisely that you regret at the time you give a git reset command. Let's say we have this:

    A - B - C - D <- HEAD
    

    Here are some possible regrets and what to do about them:

    1. I regret that B, C, and D are not one commit.

    git reset --soft A. I can now immediately commit and presto, all the changes since A are one commit.

    2. I regret that B, C, and D are not ten commits.

    git reset --mixed A. The commits are gone and the index is back at A, but the work area still looks as it did after D. So now I can add-and-commit in a whole different grouping.

    3. I regret that B, C, and D happened on this branch; I wish I had branched after A and they had happened on that other branch.

    Make a new branch otherbranch, and then git reset --hard A. The current branch now ends at A, with otherbranch stemming from it.

    (Of course you could also use a hard reset because you wish B, C, and D had never happened at all.)

    0 讨论(0)
  • 2020-11-22 15:15

    In the simplest terms:

    • --soft: uncommit changes, changes are left staged (index).
    • --mixed (default): uncommit + unstage changes, changes are left in working tree.
    • --hard: uncommit + unstage + delete changes, nothing left.
    0 讨论(0)
  • 2020-11-22 15:15

    Please be aware, this is a simplified explanation intended as a first step in seeking to understand this complex functionality.

    May be helpful for visual learners who want to visualise what their project state looks like after each of these commands:

    Given: - A - B - C (master)


    For those who use Terminal with colour turned on (git config --global color.ui auto):

    git reset --soft A and you will see B and C's stuff in green (staged and ready to commit)

    git reset --mixed A (or git reset A) and you will see B and C's stuff in red (unstaged and ready to be staged (green) and then committed)

    git reset --hard A and you will no longer see B and C's changes anywhere (will be as if they never existed)


    Or for those who use a GUI program like 'Tower' or 'SourceTree'

    git reset --soft A and you will see B and C's stuff in the 'staged files' area ready to commit

    git reset --mixed A (or git reset A) and you will see B and C's stuff in the 'unstaged files' area ready to be moved to staged and then committed

    git reset --hard A and you will no longer see B and C's changes anywhere (will be as if they never existed)

    0 讨论(0)
  • 2020-11-22 15:16

    There are a number of answers here with a misconception about git reset --soft. While there is a specific condition in which git reset --soft will only change HEAD (starting from a detached head state), typically (and for the intended use), it moves the branch reference you currently have checked out. Of course it can't do this if you don't have a branch checked out (hence the specific condition where git reset --soft will only change HEAD).

    I've found this to be the best way to think about git reset. You're not just moving HEAD (everything does that), you're also moving the branch ref, e.g., master. This is similar to what happens when you run git commit (the current branch moves along with HEAD), except instead of creating (and moving to) a new commit, you move to a prior commit.

    This is the point of reset, changing a branch to something other than a new commit, not changing HEAD. You can see this in the documentation example:

    Undo a commit, making it a topic branch

              $ git branch topic/wip     (1)
              $ git reset --hard HEAD~3  (2)
              $ git checkout topic/wip   (3)
    
    1. You have made some commits, but realize they were premature to be in the "master" branch. You want to continue polishing them in a topic branch, so create "topic/wip" branch off of the current HEAD.
    2. Rewind the master branch to get rid of those three commits.
    3. Switch to "topic/wip" branch and keep working.

    What's the point of this series of commands? You want to move a branch, here master, so while you have master checked out, you run git reset.

    The top voted answer here is generally good, but I thought I'd add this to correct the several answers with misconceptions.

    Change your branch

    git reset --soft <ref>: resets the branch pointer for the currently checked out branch to the commit at the specified reference, <ref>. Files in your working directory and index are not changed. Committing from this stage will take you right back to where you were before the git reset command.

    Change your index too

    git reset --mixed <ref>

    or equivalently

    git reset <ref>:

    Does what --soft does AND also resets the index to the match the commit at the specified reference. While git reset --soft HEAD does nothing (because it says move the checked out branch to the checked out branch), git reset --mixed HEAD, or equivalently git reset HEAD, is a common and useful command because it resets the index to the state of your last commit.

    Change your working directory too

    git reset --hard <ref>: does what --mixed does AND also overwrites your working directory. This command is similar to git checkout <ref>, except that (and this is the crucial point about reset) all forms of git reset move the branch ref HEAD is pointing to.

    A note about "such and such command moves the HEAD":

    It is not useful to say a command moves the HEAD. Any command that changes where you are in your commit history moves the HEAD. That's what the HEAD is, a pointer to wherever you are. HEADis you, and so will move whenever you do.

    0 讨论(0)
  • 2020-11-22 15:18

    In these cases I like a visual that can hopefully explain this:

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

    So each effect different scopes

    1. Hard => WorkingDir + Index + HEAD
    2. Mixed => Index + HEAD
    3. Soft => HEAD only (index and working dir unchanged).
    0 讨论(0)
  • 2020-11-22 15:19

    When you modify a file in your repository, the change is initially unstaged. In order to commit it, you must stage it—that is, add it to the index—using git add. When you make a commit, the changes that are committed are those that have been added to the index.

    git reset changes, at minimum, where the current branch (HEAD) is pointing. The difference between --mixed and --soft is whether or not your index is also modified. So, if we're on branch master with this series of commits:

    - A - B - C (master)
    

    HEADpoints to C and the index matches C.

    When we run git reset --soft B, master (and thus HEAD) now points to B, but the index still has the changes from C; git status will show them as staged. So if we run git commit at this point, we'll get a new commit with the same changes as C.


    Okay, so starting from here again:

    - A - B - C (master)
    

    Now let's do git reset --mixed B. (Note: --mixed is the default option). Once again, master and HEAD point to B, but this time the index is also modified to match B. If we run git commit at this point, nothing will happen since the index matches HEAD. We still have the changes in the working directory, but since they're not in the index, git status shows them as unstaged. To commit them, you would git add and then commit as usual.


    And finally, --hard is the same as --mixed (it changes your HEAD and index), except that --hard also modifies your working directory. If we're at C and run git reset --hard B, then the changes added in C, as well as any uncommitted changes you have, will be removed, and the files in your working copy will match commit B. Since you can permanently lose changes this way, you should always run git status before doing a hard reset to make sure your working directory is clean or that you're okay with losing your uncommitted changes.


    And finally, a visualization: enter image description here

    0 讨论(0)
提交回复
热议问题