读书笔记 --《Pro Git》
关于《Pro Git》的阅读笔记,查漏补缺,补充Git的相关知识。
资料
对象模型
Git保存的并不是文件差异,而是一系列不同时刻的被修改文件的快照。可以把Git理解为一个本地的内容寻址文件管理系统,管理着众多版本的文件。
下图是Git保存的对象,其利用树结构指向不同的版本。
Blob
Blob通常用来存储文件内容,做文件镜像使用。
Tree
在工作区做的变更使用树形来维护,树可以指向Blob,也就是变更文件,或者指向其他的树来关联未变更的文件。
Commit对象
Commit对象指向一个tree对象,另外Commit中还保存着相关提交者信息,以及上一个提交,一个Commit可能存在多个parent对象,比如两个分支汇聚到一点,产生的这个commit就会有两个parent。
Tag
Tag指向一个Commit对象。
工作模型
Git的工作模型揭露了我们在git项目中所采取的操作造成的影响。
Work Directory:工作空间,就是被Git所管理的本地项目目录。
Index:可以理解为Git的暂存区。
Head:当前所在的分支,其指向当前已经commit的最新内容。
1. 本地添加文件
本地添加只会改变work directory
2. git add
添加到暂存区,本质上是把本地目录修改的文件copy一份到Index区域。
3. git commit
Commit之后Head对应的本地分支中也会多一份文件镜像。
了解了这些那么很多命令就很好理解了。
1. git status
status实际上就是比较三个空间的差异,Index区域使用绿色,work directory使用红色。
2. git reset
reset操作有三个等级,--soft
下只会回滚HEAD区域的文件内容。--mixed
会回滚HEAD以及INDEX区域的内容。--hard
则会回滚全部区域的内容。
3. git revert
revert的操作可以理解在Work Directory把对应commit的修改全部撤销掉,然后添加到INDEX区域 ,最后合并到HEAD区域产生一个新的commit。
操作
删除已提交文件
1 | git rm --cached <文件名> # 从已提交的内容中删除文件,删除后重新提交即可删除远程仓库的该文件。 |
修补提交
工作中经常遇到提交了commit之后发现有东西忘记提交了,然后又起了一个commit,实际上可以通过修改最后一次提交方式搞定。
1 | # 该命令本质是把暂存区的文件和最后一次提交并入一起,如果指定了文件名,则把该文件与最后一次提交并入一起。 |
变基Rebase
当前在experiment分支,执行git rebase master
,Git会进行如下操作:
- 找到C4,C3最近的共同祖先C2
- 找到C2-C4之间的所有变更文件,存为临时文件。
- 将当前分支Head指向C3
- 依次把临时文件应用在C3,这个过程中会产生冲突,产生则需要手动订正,然后
git rebase --continue
继续apply
Rebase原则:“只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作”
pull –rebase
普通的pull
=fetch
+merge
,pull --rebase
=fetch
+rebase
reset –hard误操作
一个迭代分支可能是C1 -> C2 -> C3
,然后执行git reset --hard C1
,那么C2和C3的修改 就会丢失,此时没有指向他们的引用,不过因为Git每次都是镜像存储,因此只需要找到C2和C3对应的提交ID,即可恢复。
使用git reflog
查看HEAD指针改变的历史记录,从中找到对应的CommitId,使用“git branch newbranch commitId”
创建一个新的分支,指向该次提交,找回丢失的文件。
引用日志会被清理的,如果没有则可以使用git fsck --full
,该命令列出所有未被其他对象指向的commitId。
大文件删除
假设某人误操作向Git中提交了大文件,产生了一个commit,然后删除了该大文件,又产生了一个commit,对于之后的人clone,由于要拉下来完整的变更,因此每次都需要下载含有大文件的镜像。
解决方案是找到大文件的历史提交,然后重写对应的提交以及之后的提交。
git verify-pack -v .git/objects/pack/压缩pack.idx | sort -k 3 -n | tail -3
,pack指定你自己的,该命令列出比较大的一些commitIdgit rev-list --objects --all | grep commitId
,使用该命令查看该次commitId提交的大文件名称git log --oneline --branches -- 文件名
,使用该命令查看对该文件进行过改动的提交,记录下第一个改动的idgit filter-branch --index-filter \ 'git rm --ignore-unmatch --cached 文件名' -- 第一次改动Id^..
,执行该命令,重写第一次提交大文件之后的所有相关修改,使用git rm --cached
来删除之前的提交记录。rm -rf .git/refs/original
,rm -rf .git/logs
,git gc
,移除包含有旧提交指针的文件,并且 重新打包。
撤销合并
有时候已经合并到了master分支,但是需要回滚代码,那么就涉及撤销操作。
revert方式
在git提交信息中,commit分为两种,一种是开发提交的commit,一种是merge产生的commit,对于merge commit一般会有两个parent节点。git revert
一般有两种形式:git revert <commit id>
,撤销指定的commit,Git会把该commit的修改全部撤销,并产生一个新的commit。git revert -m 1 <merge commit id>
,-m参数表示两个合并父节点的第一个还是第二个,该操作会把对应的合并内容全部撤销,并产生一个新的commit。
注意revert掉的分支在此合并会出现无法合并的现象,因为撤销后被撤销的分支实际上与当前仓库没有文件关联,解决方案是撤销Revert节点,然后再次合并该分支。
reset方式
找到要回滚到的commit,然后使用git reset --hard commitId
,切到对应的分支,然后push -f
强制提交覆盖,该操作虽然能够回滚,但是会相当危险,强制覆盖会造成中间提交节点的信息丢失,分布式开发下谨慎操作。
- 版权声明: 感谢您的阅读,本文由屈定's Blog版权所有。如若转载,请注明出处。
- 文章标题: 读书笔记 --《Pro Git》
- 文章链接: https://mrdear.cn/posts/readnote-pro-git.html