文章目录
link
Git的数据模型
快照
git会把文件和文件夹的历史建模为一系列快照(snapshots),其中文件又叫"blob",就是一堆字节;文件夹又叫"tree",包含对文件和文件夹名字的映射(毕竟文件夹里也可以有文件夹)。
某一时刻的一个快照可以看作是:
最顶层的tree包含一个叫foo的文件夹和一个叫baz.txt的文件,然后foo下面又包含了一个叫bar.txt的文件。
历史
git通过相关的快照来建模历史。最简单的想法,自然是顺序的历史,按时间顺序包含一系列快照。不过Git没有采用如此简单的模型。
事实上,在Git种,历史建模为快照的有向无环图。
可以把一个个快照看作是一个个节点,区别于线性模型的是,在图里,一个节点可以有多个父节点。比如在git种,分支合并后得到的快照节点就会有多个父节点。
Git种把这些快照叫做“Commit”,对一个commit的历史进行可视化展示,可能会长这样:
图里每个“o"代表一个快照,箭头指向父节点,拿第一排来说,现有坐起第一个o,然后才有第二个o这样。第三个快照之后,出现了分支,比如说有两个不同的功能要进行平行的开发,最后可能进行分支合并得到新的快照,比如:
Git中的commit是不可变的,改动后只会生成新的commit。
数据模型
用伪代码来表示Git的数据模型可以如下图所示:
对象和content-addressing
Object,对象,在Git里指的是一个blog、一个tree或者一个commit。
type object = blob | tree | commit
在Git的数据存储中,所有的object是通过哈希(SHA-1 hash)来进行内容寻址的(content-addressing)。
可以理解为每个object通过哈希算出一个ID,然后根据这个ID来获得object。这个ID其实就是我们查看GIt历史的时候那一个个很长的字符串。而且blob tree commit都可以看作是object,当object引用其他object的时候,只要引用哈希后的ID就行。
比如,在这个结构里,可视化一下最顶层的结构(git cat-file -p 698281bc680d1995c5f4caaf3359721a5a58d48d
),
可以看到类似这样的结果:
顶层结构包含指向baz.txt和foo文件夹的指针。如果继续去看baz.txt的ID所指向的内容(git cat-file -p 4448adbf7ecd394f42ae135bbeed9676e894af8
),可以看到这样的内容:
references
现在,所有的commit都可以用一串哈希之后的ID来标识,但是对人而言,很难记住40位的16进制字符串。
对此,Git提出reference,将这串ID再映射为人类可读的名字。reference是可变的,通常会指向最新的提交
这样就可以用人类可读的名字标识一串哈希ID了,而标识“我们当前在哪”的是HEAD
repositories
这个repository指的就是Git的objects和references,Git所有在磁盘上的存储就是objects和references,git命令就是操纵commits的DAG,实现增加objects或者修改/增加references。在进行命令操作的时候,可以想一想会对这个DAG产生怎样的操作;同理,想要实现对DAG的某种操作,往往也有对应的git命令。
Staging area
通过staging area可以明确哪些改变需要提交成为shapshot哪些不用
Git命令行接口
更详细的部分可以看Pro git
基础
-
git help <command>
: get help for a git command -
git init
: creates a new git repo, with data stored in the .git directory -
git status
: tells you what’s going on -
git add <filename>
: adds files to staging area -
git commit
: creates a new commit. Write good commit messages! -
git log
: shows a flattened log of history -
git log --all --graph --decorate
: visualizes history as a DAG -
git diff <filename>
: show changes you made relative to the staging area -
git diff <revision> <filename>
: shows differences in a file between snapshots -
git checkout <revision>
: updates HEAD and current branch
分支和合并
git branch
: shows branchesgit branch <name>
: creates a branchgit checkout -b <name>
: creates a branch and switches to it
same asgit branch <name>; git checkout <name>
git merge <revision>
: merges into current branchgit mergetool
: use a fancy tool to help resolve merge conflictsgit rebase
: rebase set of patches onto a new base
远程
git remote
: list remotesgit remote add <name> <url>
: add a remotegit push <remote> <local branch>:<remote branch>
: send objects to remote, and update remote referencegit branch --set-upstream-to=<remote>/<remote branch>
: set up correspondence between local and remote branchgit fetch
: retrieve objects/references from a remotegit pull
: same asgit fetch; git merge
git clone
: download repository from remote
undo
git commit --amend
: edit a commit’s contents/messagegit reset HEAD <file>
: unstage a filegit checkout -- <file>
: discard changes
高级git
git config
: Git is highly customizablegit clone --depth=1
: shallow clone, without entire version historygit add -p
: interactive staginggit rebase -i
: interactive rebasinggit blame
: show who last edited which linegit stash
: temporarily remove modifications to working directorygit bisect
: binary search history (e.g. for regressions)
.-gitignore
: specify intentionally untracked files to ignore
其他
- GUI git是有GUI的,不过不是太推荐
- shell 集成:最好是在shell里集成git,一般zsh好像自动会有
- editor集成:也很方便,典型的有fugitive.vim
- 工作流:在大型项目中的实践有很多方法
- github:有很多优值项目可以pull request
- 除了github,还有gitlab bitbucket等
- 非常推荐阅读Pro git
- Oh shit git提供了一个简单的教程,从常见的git问题中恢复
- Git for computer scientists简单解释了Git的数据模型,比本博客有跟多的图示
- Git from the bottom up详细介绍了Git的机制,适合更好奇的人去了解
- How to explain git in simple words
- Learn git branching一个基于浏览器的游戏,可以教你git
练习
1、如果之前完全没用过Git的话,先看一下Pro git的前几章或者Learn git brnching
2、clone project,可视化看看历史,谁是最后修改README.md的(提示,用git log加上argument)?最后修改collections中_config.yml这行的提交的message是什么?(提示,用git blame和git show)
git clone https://github.com/missing-semester/missing-semester.git
git log --all --graph --decorate
git log README.md
git blame _config.yml # 查看collections那一行是谁改的
git show a88b4eac # 对照差出来的ID看Message
3、Git中常常出现的一个错误是不小心把特别大或者敏感文件。试着添加一个文件到repositority,做一些提交,然后把这个文件从历史里删掉
wget bfg的地址
java -jar bfg-1.14.0.jar -D sensifile.py
4、对一个项目进行修改,然后进行git stash
,运行git log --all --oneline
,运行git stash pop
来撤销
5、在~/.gitconfig中加上别名,运行git graph
得到git log --all --graph --decorate --oneline
的结果。
6、可以运行git config --global core.excludesfile ~/.gitignore_global
后在~/.gitignore_global
中定义忽略的文件,设定忽略一些系统文件
创建文件后加上*.DS_Store
7、提交一个pull request