版本控制
之前自己使用Git客户端版在Windows平台乱搞的时候,因为之前在Github上有一个一样的项目仓库。然后手贱点击了reset按钮(应该是这个)结果发现Android Studio整个项目都没见了,吓得我半死。赶快百度百度,最后在shell里面使用了git reset命令解救了项目,吓得我赶快备份。这也给了我一个教训,做事情一定要谋定后动,没有完全了解之前不要随意使用。
言归正传,今天写的是关于git的版本控制的,简单说就是版本退回和返回现在。
在git的仓库之中,有一个名为HEAD的指针,它指向的是当前版本的版本号。它指向哪个版本号,现在就显示哪个版本。
如果你想要返回某个版本,可以首先使用命令git log命令查看历史记录。
git log命令会显示commit ID, Author,Date以及你每次提交的标题。
git reflog命令显示记录的每次命令
需要注意的是commit ID是一个SHA-1 hash值,它用来校验数据的完整性,它可以保证在很多年以后,你checkout某个commit时,完全和之前是一样的。
现在使用命令git reset --hard HEAD^ 当使用完这个命令之后,可以查看文件,发现回到了上次修改之前的样子。而且整个区域都是干净的,即三个区域文件都是一样的。在Git中,HEAD表示当前版本,上个版本是HEAD^,上上个就是HEAD^^,更多的版本使用HEAD~20(第前20个版本)。
这样虽然已经回到过去了,可是如果想要再次来到现实的话,这个时候commit ID就派上了用场了
命令git reset --hard 546321(commit ID,一般只需要输出六位就行了,GIt会自动去寻找。只要git历史中前六位没有相同的)
修改控制
如果自己疏忽,在工作区写下错误的代码的时候,可以采取两种方式来删除错误的代码。
1.是常见的手动打开文件删除
2.使用git checkout -- filename来删除文件修改。
这里要注意一下,使用git checkout -- 命令是已什么作为依据来复原文件的呢?
1.如果是文件还没有使用git add命令(暂存区文件还未修改),使用git checkout -- 命令就是把暂存区的文件覆盖到工作区中。
2.如果文件已经使用了git add命令(暂存区文件和工作区是一样的),这样的话使用git checkout -- 命令是没有用的,因为暂存区的内容和工作区其实是一样的。而我们应该这样做:先把暂存区的内容返回到上次修改的地方,然后在将暂存区覆盖文件区内容。
实验
做一个实验,实验之前需要时常使用到几个命令:
git status 查看文件状态。
git diff filename比较暂存区和工作区中内容的不同
git diff HEAD -- filename 比较版本库中和工作区最新版本的区别。
实验如下:一个readme.txt文件,现在记录着的文件内容为"no 1"先用
git add命令和
git commit命令让整个最新的版本库,暂存区,工作区内容一致。使用
git diff和
git diff HEAD -- readme.txt命令查看是否一致。
然后我在工作区做修改,添加一行内容,让文件变成"no 1 no 2",使用git status 发现一个没有提交的修改,用git diff 查看
git提示删除了"no 1",添加了"no 1 no 2"。
实验一、(未使用git add命令时)这个时候使用git checkout -- readme.txt之后,查看readme.txt文件的内容,已经恢复到"no 1"了。
实验二、(当已经使用完git add命令之后)当你修改了readme.txt文件之后,而且还使用了git add命令。这个时候暂存区的readme.txt文件也已经变成了"no 1 no 2"了。使用git diff命令,发现没有任何输出,证明了工作区和暂存区内容一致。而使用git diff HEAD -- readme.txt发现
即版本库中readme.txt文件的内容还是"no 1"。
这个时候使用git reset HEAD readme.txt命令,输出
Unstaged changes after reset:,再用git diff命令发现
这个时候暂存区的内容已经和工作区内容不一样了。这个时候再用git checkout -- readme.txt命令,就可以撤销这次提交了。
注意:任何修改如果没有使用git add命令的话,那么结果往往是悲剧的。
假设你之前是"no 1"然后你修改成了"no 1 no 2"并且这个时候使用了git add命令。你再修改工作区的文件为"no 1 no 2 no 3",这个时候如果你使用git checkout -- readme.txt命令的话,最后也会回到"no 1 no 2",不能再 回到"no 1"了。
一个bug
廖雪峰老师对于git reset HEAD readme.txt的解释是
可是经过我的测试,发现并没有放回工作区。
假设说我使用完 git add命令之后,暂存区和工作区是一致的,然后使用 git reset HEAD readme.txt命令之后,再使用git diff,发现暂存区是和工作区是不同的,所以说git reset HEAD readme.txt命令只是撤销了这次add提交。
删除控制
假如在资源管理器或者用rm命令删除了文件时,使用git会提示你:有两个选择,一个是使用git rm 删除掉文件,然后使用git commit命令保证版本库和工作区文件一致。还有一个就是防止误删,就是使用git checkout -- filename命令来回复删除的文件。
ps:看的我自己的好累,果然看别人写的东西真是难受。。。。。。
最后的问题
当使用了git reset HEAD命令之后,暂存区恢复到上次的情况,那么这个恢复是通过什么来判断的呢?
一是:暂存区本身就有一个类似于HEAD的指针,使用reset之后就可以让指针指回上个版本(就像撤销)。
二是:将版本库中的文件覆盖到暂存区,这种想法就是说暂存区就只是单纯的一个存储内容的区域,没有HEAD指针。
我感觉是第二种,之前看到一张图。无论是暂存区还是 master分支都只是一个树状的目录,而object是另外存储的在一个objects对象库之中。既然是这样的话,那么说无论怎么改都只是目录的改变,最重要的还是看objects对象库之中的对象的引用是否改变
(突然想到只有git diff (比较工作区和暂存区)以及git diff HEAD --(比较工作区和版本库),而没有比较暂存区和版本库,因为他们都是使用一个对象库的)。
感觉有点思路,但还是迷迷糊糊的,希望有大神可以指导一下,感谢!