git reset命令原理详解(转)

HEAD

HEAD也是很多初学者会搞不清楚的一个概念 说穿了也很简单 就是

你的目前branch的最新的commit
假设这是目前的git log, HEAD指向master的最新的commit

所以今天你下了git checkout b1
HEAD就会指向你checkout的那个branch的tip

但有个例外 因为checkout并不只可以指定branch 还可以指定一个commit 所以当你checkout <commit>
clipboard.png

他的意思是说 嘿 既然你指定的是commit 我就生一个暂时的branch给你 你现在的确在一个branch上 只是这个branch没有名字 你可以马上checkout -b 生出一个branch 也可以commit在这个没有名字的branch上面
clipboard.png

再说一次 HEAD就是你的目前branch的最新的commit 即使这个branch可能没有名字

git reset

git reset [ –soft | –mixed | –hard] <commit>

git reset <commit> 的意思就是 把HEAD移到<commit>

这是现在repo的情况
clipboard.png

D在stage裡面, E在working裡

我习惯想像成这样 红色就是还没进staging 绿色就是还没commit
clipboard.png

这裡的repo是指local的 不是remote的 别忘了一个铁则 Working >= Staging >= Repo

这样具体化之后 之后的解释会简单很多

再说一次 git reset <commit> 的意思就是 把HEAD移到<commit> 就是把你现在这个branch的最新的commit移到你指定的commit

soft就是只动repo
mixed就是动repo还有staging(这个是默认参数)
hard就是动repo还有staging还有working

你只要知道这三种用法就可以

现在的State是S0 因为等一下会一直回到现在的state, S0的HEAD在Repo的C

SOFT

soft 就是只动repo

这样子 staging裡面就会有c和d, working 裡e一样

git reset --soft <B commit>

clipboard.png

HEAD会跑到repo的B

MIXED/DEFAULT

状态回到S0

mixed就是动repo还有staging

这样子 staging裡面就什麽都没有, working 裡c,d,e

git reset --mixed <B commit>

clipboard.png

HEAD会跑到repo的B

HARD

状态回到S0

hard就是动repo还有staging还有working

这样子 staging裡面就什麽都没有, working 裡什麽都没有

git reset --hard <B commit>

clipboard.png

HEAD会跑到repo的B

git reset第二种用法

git reset <commit> [--] <file>

第二种的用法只是第一种的一个特例 就是前面的soft/mixed/hard不能指定 使用默认的mixed

然后后面可以指定单独的file

(先不要管[--])这个用法就是你可以只针对一个file做出这个指令

git reset --mixed <commit>

至于--(double hyphen) 是避免有些人会把档案名称取的跟branch名称一样 或是你有个档案就叫做"HEAD" 你就必须用 -- HEAD 而不是只用HEAD 但基本上你不胡搞 你是不需要用到这个的

还有一件事 如果你commit不给 default就是HEAD, 如果你file不给 default就是整个资料夹

恭喜走出十里坡
基本上git reset已经讲完了 你看到一个git reset的command你就知道执行下去会发生什麽事 但看到command知道会发生什麽事只是学git的第一步而已 你要知道什麽时候要用这个command才是高手 以下说明常遇到 需要用git reset的例子

扩展阅读(实例说明)

Unstage
有没有看到那精美的

(use "git reset HEAD ..." to unstage)

为什麽可以呢 因为default是–mixed 所以白话文就是把HEAD移到HEAD(就是不要动的意思) 然后staging跟著变 这就代表把staging的状态跟HEAD的状态搞成一样

所以要是从S0下这个指令

git reset HEAD d
会变这样
clipboard.png

虽然会变成这样是因为staging变得跟repo一样 但你用git status看一下
clipboard.png

感觉会像是d从staging变到working去了 所以结果看起来像是"unstage"

当然你要unstage所有的file就是

git reset HEAD
举一反三 你要unstage而且要把他们从working拿掉 就是

git reset --hard HEAD 
Undo commit
这大概是数一数二常见的问题 stackoverflow上问如何undo last commit的这题有一万多个讚 事实上也很简单 原本状态是这样
clipboard.png
下这个指令后

git reset --soft HEAD~
就变这样 轻松
clipboard.png

在错的branch上开发
还有一个蛮常见的情况 你要开发前要先跟远端的origin/master sync, sync完后你忘记换到自己的feature branch而是直接在master上开发 写了两个commit后突然发现写错branch 该怎麽办呢

现在情况是这样
clipboard.png

git branch feature_branch
複製一个新的branch 变成这样
clipboard.png

git reset --hard origin/master
clipboard.png

git checkout feature_branch
clipboard.png

Squash commit
另一个用法 也是我写这篇文章的原因 是我上礼拜要check in我的code进prod的时候 我必须把我所有local的commit变成一个commit 我们组的Tech lead问我说该怎麽做 我跟他说 嘿嘿我知道 用git interactive rebase 他说那个比较麻烦 要选来选去 只要下一个简单的git reset就可以 我才大彻大悟 原来之前做学问没有读通 把简单的事搞複杂了

假设现在要把CDE squash成一个commit push到remote 现在状态是这样
clipboard.png

这时候下个精美的

git reset --soft HEAD~3
就会变这样
clipboard.png

那事实上上面那张跟下面那张是同一件事
clipboard.png

再下个git commit就搞定了

最后一题
最后来考一下这题 看大家是不是真的懂 小心是个陷阱题

这是现在的State:
clipboard.png

请问下完这个command之后

git reset --hard HEAD~1
会变成什麽样子呢

(A)
clipboard.png
(B)
clipboard.png
(C)
clipboard.png

答案是B 你答对了吗?

猜你喜欢

转载自blog.csdn.net/dshf_1/article/details/80825347
今日推荐