Git - 高级篇 (5)

     来聊聊 checkout 吧, 以及碰到紧急打包这种事儿.

checkout 的本质

     在前面的 branch 的部分,我说到 checkout 可以用来切换 branch

1
git checkout branch2


     不过实质上,checkout 并不止可以切换 branchcheckout 本质上的功能其实是:签出( checkout )指定的 commit

     git checkout branch名 的本质,其实是把 HEAD 指向指定的 branch,然后签出这个 branch 所对应的 commit 的工作目录。所以同样的,checkout 的目标也可以不是 branch,而直接指定某个 commit

1
git checkout HEAD^^
1
git checkout master~5
1
git checkout 78a4bc
1
git checkout 78a4bc^

     这些都是可以的。

     另外,如果你留心的话可能会发现,在 git status 的提示语中,Git 会告诉你可以用 checkout -- 文件名 的格式,通过「签出」的方式来撤销指定文件的修改:



checkout 和 reset 的不同

     checkoutreset 都可以切换 HEAD 的位置,它们除了有许多细节的差异外,最大的区别在于:reset 在移动 HEAD 时会带着它所指向的 branch 一起移动,而 checkout 不会。当你用 checkout 指向其他地方的时候,HEAD 和 它所指向的 branch 就自动脱离了。
     事实上,checkout 有一个专门用来只让 HEADbranch 脱离而不移动 HEAD 的用法:

1
git checkout --detach

     执行这行代码,Git 就会把 HEADbranch 脱离,直接指向当前 commit



小结

     checkout 的本质是签出指定的 commit,所以你不止可以切换 branch,也可以直接指定 commit 作为参数,来把 HEAD 移动到指定的 commit

紧急情况:「立即给我打个包,现在马上!」

     前面在讲 branch 的时候讲到,利用 branch 可以实现一人多任务的需求,从而可以轻松应对「嘿,这个先别做了,给你个新活」的情况。但有时,尤其是在互联网公司,你可能会遇到比这更紧急的情况:你正对着电脑发呆,忽然见到一个同事屁股着着火就跑来找你了:「快快快,立即给我打个包,现在马上,拜托拜托!」
     这种情况和「这个 branch 先放放吧」不同,你没时间、也没必要当场慌慌张张把文件的所有改动做个临时的 commit 然后去救同事的火,救完火再重新把 commit 撤销回来。这时候你只要先把所有文件一股脑扔在一边就可以去给同事打包了,打完包再把刚才扔到一边的文件重新取过来就好。
     这一「扔」一「取」,用的是 Git 的 stash 指令。

stash:临时存放工作目录的改动

     “stash” 这个词,和它意思比较接近的中文翻译是「藏匿」,是「把东西放在一个秘密的地方以备未来使用」的意思。在 Git 中,stash 指令可以帮你把工作目录的内容全部放在你本地的一个独立的地方,它不会被提交,也不会被删除,你把东西放起来之后就可以去做你的临时工作了,做完以后再来取走,就可以继续之前手头的事了。
     具体说来,stash 的用法很简单。当你手头有一件临时工作要做,需要把工作目录暂时清理干净,那么你可以:

1
git stash

     就这么简单,你的工作目录的改动就被清空了,所有改动都被存了起来。
     然后你就可以从你当前的工作分支切到 master 去给你的同事打包了……
     打完包,切回你的分支,然后:

1
git stash pop

branch 删过了才想起来有用?

     branch 用完就删是好习惯,但有的时候,不小心手残删了一个还有用的 branch ,或者把一个 branch 删掉了才想起来它还有用,怎么办?

reflog :引用的 log

     reflog 是 “reference log” 的缩写,使用它可以查看 Git 仓库中的引用的移动记录。如果不指定引用,它会显示 HEAD 的移动记录。假如你误删了 branch1 这个 branch,那么你可以查看一下 HEAD 的移动历史:

1
git reflog


     从图中可以看出,HEAD 的最后一次移动行为是「从 branch1 移动到 master」。而在这之后,branch1 就被删除了。所以它之前的那个 commit 就是 branch1 被删除之前的位置了,也就是第二行的 c08de9a
     所以现在就可以切换回 c08de9a,然后重新创建 branch1

1
2
git checkout c08de9a
git checkout -b branch1

     这样,你刚删除的 branch1 就找回来了。

注意:不再被引用直接或间接指向的 commits 会在一定时间后被 Git 回收,所以使用 reflog 来找回删除的 branch 的操作一定要及时,不然有可能会由于 commit 被回收而再也找不回来。

查看其他引用的 reflog

     reflog 默认查看 HEAD 的移动历史,除此之外,也可以手动加上名称来查看其他引用的移动历史,例如某个 branch

1
git reflog master


~感谢捧场,您的支持将鼓励我继续创作~