5分钟学习git内部原理
每天与你分享
IT编程开发 技术干货 架构方案 技术思维导图 设计模式 算法题库
GIT内部原理
每天5分钟学习一项技能,让我们先来看个大概的视图:
前言聊一聊
了解Git是储存信息的过程
下面会用一个显而易见的例子让大伙感受一下git是怎么储存信息的。
首先我们先创建两个文件
git init
echo 'codebox111' > file1.txt(a.txt)
echo 'codebox222' > file2.txt(b.txt)
git add *.txt
这时候,Git会将整个数据库储存在.git/
目录下,如果你此时去查询.git/objects
目录,你会看到仓库里面多了两个object。
tree .git/objects.git/objects
├── 58
│ └── c9bdf9d017fcdaasdasdas8c073cbfcbb7ff240d6c
├── c2
│ └── 00906efd24ec5e783bsdaee7f23b5d7c941b0c12c
├── info
└── pack
我们来看一下里面究竟存的是什么玩意
cat .git/objects/58/c9bdf9d017fcd178dc8c073cbfcbb7ff240d6cxKOR0a044K%
一串乱码是什么鬼?这是因为Git将信息压缩成二进制文件了。但是不用害怕,因为Git也提供了一个能够帮助你探索它的api命令 git cat-file [-t] [-p]
, -t
可以查看object的类型,-p
可以查看object储存的具体内容:
git cat-file -t 5xsadsa
git cat-file -p 5sdadasd
$ git commit -am '[+] init'$ tree .git/objects.git/objects
├── 0c
│ └── 96bfcsadasddddxxxasd18f46c7e47ab2
├── 4c
│ └── aaaxasdasdasdf0716ddd5b209
...
cat-file
命令,看看它们分别是什么类型以及具体的内容是什么:
$ git cat-file -t 4cxxree$ git cat-file -p 4caaa1100644 blob 58c9bdf9d017fcd178dc8c0... file1.txt(a.txt)
100644 blob c200906efd24ec5e783bee7... file2.txt(b.txt)
git cat-file -t 0c9xxf
commit
git cat-file -p 0cxasd1f
tree 4caaa1a9asadadad367xef071616e5b209
author lsan 李3 123331343 +0800
committer lsi 李4 133312102343 +0800
init
然后我们发现了第2种Git object类型——commit,它储存的是一个提交的信息,包括对应目录结构的快照tree的哈希值,上一个提交的哈希值(这里由于是第一个提交,所以没有父节点。在一个merge提交中还会出现多个父节点),提交的作者以及提交的具体时间,最后是该提交的信息。
此时我们去看Git仓库是这样的:
到这里我们就知道Git是怎么储存一个提交的信息的了,那有同学就会问,我们平常接触的分支信息储存在哪里呢?
cat .git/HEADref: refs/heads/master
cat .git/refs/heads/mastedsadas3331c7e47ab2
在Git仓库里面,HEAD、分支、普通的Tag可以简单的理解成是一个指针,指向对应commit的SHA1值。
git tag -a
)的时候会新建,这里不详细介绍说明了,有兴趣的朋友按照上文中的方法可以自己去深入探究。
看看Git的三个分区
-
第一点:工作目录 ( working directory ):操作系统上的文件,所有代码开发编辑都在这上面完成。 -
第二点:索引( index or staging area ):可以理解为一个暂存区域,这里面的代码会在下一次commit被提交到Git仓库。 -
第三点:Git仓库( git repository ):由Git object记录着每一次提交的快照,以及链式结构记录的提交变更历史。
运行echo "333" > file1.txt
将file1.txt(a.txt)的内容从111修改成333,此时如上图可以看到,此时索引区域和git仓库没有任何变化。
执行git add file1.txt把
file1.txt(a.txt)加入到索引区域,如图所示,git在仓库里新建一个blob object,储存了新的文件内容和更新了索引将flie1.txt指向了新建的blob object。
运行git commit -m 'update'
提交这次修改。如上图所示
第一:Git先根据当前的索引生产一个tree object,当是新提交的一个快照。
第二:创建一个新的commit object,把这次commit的信息储存起来,parent指向上一个commit,组成一条链记录变更历史。
第三:把master分支的指针移到新的commit结点。
至此知道了Git的三个分区和作用、历史链的建立原由。Git的大部分指令都是在操作这三个分区和这条链。
git相关操作命令复习一下
Git提交记住用户名和密码
https://www.jianshu.com/p/6c539d1956d5
创建版本库
git clone <url>
克隆远程版本库git init
初始化本地版本库远程仓库管理
git remote
查看远程仓库git remote remove 远程库名字
git删除远程库git remote add origin http://XXX.git
git添加远程库git remote rename origin mypython
修改远程库名称文件操作
git rm 文件名
删除文件git mv config.php ./inc/config.php
对文件移动或改名创建和提交
git checkout -b dev
创建并切换到分支从已有的分支创建新的分支(如从master分支),创建一个dev分支git push origin dev
提交该分支到远程仓库git branch -d <BranchName>
删除本地分支git branch -a | -r
查看项目的分支们(包括本地和远程) -r 查看远程的分支git status
查看状态git diff
查看变更内容git add .
跟踪所有改动过的文件git add <file>
跟踪指定的文件git mv <old><new>
文件改名git rm --cached <file>
删除文件git commit -m "commit message"
停止跟踪文件但是不删除git commit --amend
修改最后一次提交查看提交历史
git reflog
查看版本变化git log
查看提交历史git log --pretty=oneline
查看提交历史-单行显示git log -p <file>
查看指定文件的提交历史git blame <file>
以列表方式查看指定文件的提交历史撤销
git reset --hard HEAD
撤销工作目录中所有未提交文件的修改内容git checkout HEAD <file>
撤销指定的未提交文件的修改内容git revert <commit>
撤销指定的提交分支和标签
git branch
显示所有本地分支git checkout <branch/tag>
切换到指定分支或标签git branch <new-branch>
创建新分支git branch -d <branch>
删除本地分支git tag
列出所有本地标签git tag <tagname>
基于最新提交创建标签git tag -d <ragname>
删除标签(本地)git push origin :refs/tags/v1.0.0
删除github远端的指定taggit push origin --tags
共享标签合并与衍合
git merge <branch>
合并指定分支到当前分支git rebase <branch>
衍合指定分支到当前分支解决合并的冲突
先git status 查看一下冲突的文件
然后修改内容add+commit提交
最好git push 并删除分支
tag标签
git tag -a t1 -m "标签"
添加一个t1的标签git show t1
git push origin t1
推送到远程版本回退
git reset --hard f0bc0ab5a32a6780b913a74ae9761c0ce1680ef0
回退到指定的版本号-可以用git log查看git push -f -u origin master
强制提交到master分支(具体哪个分支请酌情修改)远程操作
git remote -v
查看远程版本信息git remote show <remote>
查看指定远程版本信息git remote add <remote> <url>
添加远程版本库git fetch <remote>
从远程库获取代码git pull <remote> <branch>
下载代码及快速合并git push <remote> <branch>
上传代码及快速合并git pull <remote> :<branch/tag-name>
删除远程分支或标签git push --tags
上传所有标签初始配置
git config --global user.name "xxx"
git config --global user.email "[email protected]"
git remote set-url origin git+ssh:[email protected]:cbtp/daone-rating-project.git
git clone [email protected]:cbtop/daoone-rating-project.git
一些有趣的问题
问题1:为什么要把文件的权限和文件名储存在tree object里面而不是blob object呢?
问题2:每次commit,Git储存的是全新的文件快照还是储存文件的变更部分?
问题3:Git怎么保证历史记录不可篡改?
推荐阅读