HEAD
HEAD也是很多初学者会搞不清楚的一个概念 说穿了也很简单 就是
你的目前branch的最新的commit
所以今天你下了git checkout b1
但有个例外 因为checkout并不只可以指定branch 还可以指定一个commit 所以当你checkout <commit>
他的意思是说 嘿 既然你指定的是commit 我就生一个暂时的branch给你 你现在的确在一个branch上 只是这个branch没有名字 你可以马上checkout -b 生出一个branch 也可以commit在这个没有名字的branch上面
再说一次 HEAD就是你的目前branch的最新的commit 即使这个branch可能没有名字
git reset
git reset [ –soft | –mixed | –hard] <commit>
git reset <commit> 的意思就是 把HEAD移到<commit>
这是现在repo的情况
D在stage裡面, E在working裡
我习惯想像成这样 红色就是还没进staging 绿色就是还没commit
这裡的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>
HEAD会跑到repo的B
MIXED/DEFAULT
状态回到S0
mixed就是动repo还有staging
这样子 staging裡面就什麽都没有, working 裡c,d,e
git reset --mixed <B commit>
HEAD会跑到repo的B
HARD
状态回到S0
hard就是动repo还有staging还有working
这样子 staging裡面就什麽都没有, working 裡什麽都没有
git reset --hard <B commit>
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
会变这样
虽然会变成这样是因为staging变得跟repo一样 但你用git status看一下
感觉会像是d从staging变到working去了 所以结果看起来像是"unstage"
当然你要unstage所有的file就是
git reset HEAD
举一反三 你要unstage而且要把他们从working拿掉 就是
git reset --hard HEAD
Undo commit
这大概是数一数二常见的问题 stackoverflow上问如何undo last commit的这题有一万多个讚 事实上也很简单 原本状态是这样
下这个指令后
git reset --soft HEAD~
就变这样 轻松
在错的branch上开发
还有一个蛮常见的情况 你要开发前要先跟远端的origin/master sync, sync完后你忘记换到自己的feature branch而是直接在master上开发 写了两个commit后突然发现写错branch 该怎麽办呢
现在情况是这样
git branch feature_branch
複製一个新的branch 变成这样
git reset --hard origin/master
git checkout feature_branch
Squash commit
另一个用法 也是我写这篇文章的原因 是我上礼拜要check in我的code进prod的时候 我必须把我所有local的commit变成一个commit 我们组的Tech lead问我说该怎麽做 我跟他说 嘿嘿我知道 用git interactive rebase 他说那个比较麻烦 要选来选去 只要下一个简单的git reset就可以 我才大彻大悟 原来之前做学问没有读通 把简单的事搞複杂了
假设现在要把CDE squash成一个commit push到remote 现在状态是这样
这时候下个精美的
git reset --soft HEAD~3
就会变这样
那事实上上面那张跟下面那张是同一件事
再下个git commit就搞定了