git reset soft hard mixed 详解

本文深入讲解Git中的reset命令,区分其与checkout的区别,探讨不同参数(soft、hard、mixed)的作用及应用场景,帮助读者理解如何正确使用reset进行版本回退。

文章属于转载,原文地址

http://www.cnblogs.com/kidsitcn/p/4513297.html


GIT reset命令,似乎让人很迷惑,以至于误解,误用。但是事实上不应该如此难以理解,只要你理解到这个命令究竟在干什么。

首先我们来看几个术语

  • HEAD

这是当前分支版本顶端的别名,也就是在当前分支你最近的一个提交

  • Index

index也被称为staging area,是指一整套即将被下一个提交的文件集合。他也是将成为HEAD的父亲的那个commit

  • Working Copy

working copy代表你正在工作的那个文件集

  • Flow

当你第一次checkout一个分支,HEAD就指向当前分支的最近一个commit。在HEAD中的文件集(实际上他们从技术上不是文件,他们是blobs(一团),但是为了讨论的方便我们就简化认为他们就是一些文件)和在index中的文件集是相同的,在working copy的文件集和HEAD,INDEX中的文件集是完全相同的。所有三者(HEAD,INDEX(STAGING),WORKING COPY)都是相同的状态,GIT很happy。

当你对一个文件执行一次修改,Git感知到了这个修改,并且说:“嘿,文件已经变更了!你的working copy不再和index,head相同!”,随后GIT标记这个文件是修改过的。

然后,当你执行一个git add,它就stages the file in the index,并且GIT说:“嘿,OK,现在你的working copy和index区是相同的,但是他们和HEAD区是不同的!”

当你执行一个git commit,GIT就创建一个新的commit,随后HEAD就指向这个新的commit,而index,working copy的状态和HEAD就又完全匹配相同了,GIT又一次HAPPY了。

下面这一段是另外一个牛人的解释:

总的来说,git reset命令是用来将当前branch重置到另外一个commit的,而这个动作可能会将index以及work tree同样影响。比如如果你的master branch(当前checked out)是下面这个样子:

- A - B - C (HEAD, master)

HEAD和master branch tip是在一起的,而你希望将master指向到B,而不是C,那么你执行

git reset B以便移动master branch到B那个commit:

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

注意:git reset和checkout是不一样的。如果你运行git checkout B,那么你讲得到:

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

这时HEAD和master branch就不在一个点上了,你进入detached HEAD STATE. HEAD,work tree,index都指向了B,但是master branch却依然指向C。如果在这个点上,你执行一个新的commit D,那么你讲得到下面(当然这可能并不是你想要的,你可能想要的是创一个branch做bug fix):

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

记住git reset不会产生commits,它仅仅更新一个branch(branch本身就是一个指向一个commit的指针)指向另外一个commit(Head和branch Tip同时移动保持一致).其他的仅剩对于index和work tree(working directory)有什么影响。git checkout xxxCommit则只影响HEAD,如果xxxCommit和一个branch tip是一致的话,则HEAD和branch相匹配,如果xxxCommit并不和任何branch tip相一致,则git进入detached HEAD 状态

 

 

  • Reset

如果你仔细研究reset命令本身就知道,它本身做的事情就是重置HEAD(当前分支的版本顶端)到另外一个commit。假设我们有一个分支(名称本身无所谓,所以我们就简单称为"super-duper-feature”分支吧),图形化表示如下:

如果我们执行:

git reset HEAD

任何事情都不会发生,这是因为我们告诉GIT重置这个分支到HEAD,而这个正是它现在所在的位置。

git reset HEAD~1

当我们再执行上面的命令时(HEAD~1是“the commit right before HEAD”的别名,或者说:put differently "HEAD's parent"),我们的分支将会如下所示

如果我们执行git reset HEAD~2,则意味着将HEAD从顶端的commit往下移动两个更早的commit。

  • Parameters
  1. soft

--soft参数告诉Git重置HEAD到另外一个commit,但也到此为止。如果你指定--soft参数,Git将停止在那里而什么也不会根本变化。这意味着index,working copy都不会做任何变化,所有的在original HEAD和你重置到的那个commit之间的所有变更集都放在stage(index)区域中。

 

  2.hard

--hard参数将会blow out everything.它将重置HEAD返回到另外一个commit(取决于~12的参数),重置index以便反映HEAD的变化,并且重置working copy也使得其完全匹配起来。这是一个比较危险的动作,具有破坏性,数据因此可能会丢失!如果真是发生了数据丢失又希望找回来,那么只有使用:git reflog命令了。makes everything match the commit you have reset to.你的所有本地修改将丢失。如果我们希望彻底丢掉本地修改但是又不希望更改branch所指向的commit,则执行git reset --hard = git reset --hard HEAD. i.e. don't change the branch but get rid of all local changes.另外一个场景是简单地移动branch从一个到另一个commit而保持index/work区域同步。这将确实令你丢失你的工作,因为它将修改你的work tree!

  3.mixed(default)

--mixed是reset的默认参数,也就是当你不指定任何参数时的参数。它将重置HEAD到另外一个commit,并且重置index以便和HEAD相匹配,但是也到此为止。working copy不会被更改。所有该branch上从original HEAD(commit)到你重置到的那个commit之间的所有变更将作为local modifications保存在working area中,(被标示为local modification or untracked via git status),但是并未staged的状态,你可以重新检视然后再做修改和commit

 

积小流以汇江海,细微做起

Git 中,`git reset` 和 `git checkout` 是两个常用于管理提交历史和切换分支的命令,但它们的功能和使用场景有显著区别。 ### 功能区别 `git reset` 主要用于撤销提交或从暂存区移除文件。它作用于 Git 的三棵树之一:`HEAD`(指向当前分支的最新提交)、`index`(暂存区)和 `working directory`(工作目录)。通过不同的选项,`git reset` 可以控制撤销操作的范围: - `git reset`:默认情况下,该命令会将 `index` 树更新为与 `HEAD` 树一致,但不会影响 `working directory`。 - `git reset --mixed`:这是默认选项,与上述行为相同。 - `git reset --soft`:仅移动 `HEAD` 指针,不改变 `index` 和 `working directory`。 - `git reset --hard`:不仅移动 `HEAD` 指针,还会将 `index` 和 `working directory` 更新为与 `HEAD` 一致的状态,这会导致所有未提交的更改被丢弃[^2]。 相比之下,`git checkout` 更多用于切换分支或检出特定文件的历史版本。它可以更新 `working directory` 和 `index` 树以匹配指定的提交或分支: - `git checkout <branch>`:切换到指定的本地分支。 - `git checkout -b <new-branch>`:创建并切换到一个新的分支。 - `git checkout <commit> <file>`:从指定的提交中检出某个文件到当前的工作目录和索引中。 - `git checkout .`:放弃所有工作区的修改。 - `git checkout -- <file>`:放弃对指定文件的修改。 - `git checkout -f`:强制检出文件,即使存在冲突或未保存的更改也会被覆盖[^1]。 ### 使用场景 `git reset` 通常在需要撤销提交或清理暂存区时使用。例如,如果希望撤销最近的一次提交但保留工作目录中的更改,可以使用 `git reset HEAD~1`。而如果希望完全丢弃所有未提交的更改,则可以使用 `git reset --hard`。 `git checkout` 则适用于切换分支或恢复工作目录中的文件。例如,在开发新功能时,可能会创建一个新的分支并切换过去,使用 `git checkout -b feature-branch`。如果在当前分支中不小心修改了某些文件并且想要恢复原始状态,可以使用 `git checkout -- <file>` 来撤销这些更改。 ### 总结 虽然 `git reset` 和 `git checkout` 都能影响 Git 的三棵树,但它们的主要用途不同。`git reset` 更侧重于提交历史的修改和暂存区的操作,而 `git checkout` 更侧重于分支切换和文件版本的检出。理解这两者的区别有助于更有效地管理和维护 Git 项目。 ```bash # 示例:使用 git reset 撤销最近一次提交 git reset HEAD~1 # 示例:使用 git checkout 切换到另一个分支 git checkout main # 示例:使用 git checkout 创建并切换到新分支 git checkout -b new-feature ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值