git
Table of Contents
1 Git
1.1 内部原理1
1.1.1 底层命令(plumbing)和高层命令(porcelain)
git 根本上就是: a content_addressable filesystem(内容寻址文件系统) + VCS user interface
依次介绍如下3个内容:
- 内容文件寻址系统
- 传输机制(transport mechanisms)
- 版本库管理任务(the repository maintance tasks)
底层命令和高层命令 git 最初是 提供VCS 的 工具集, 只包含底层命令(plumbing). 而现在常用的~check, branch, remote~等都是建立在底层命令上的高层命令(porclain). 通过学习底层命令, 能够了解git的工作原理, 知道git怎么运行和为什么这么运行.
.git
目录几乎包含了 everything that Git 存储和操作. 该目录中最重要的4个条目如下:
- HEAD文件: 指向当前check out的分支
- index文件: 存储的 staging area 信息. 暂存区信息
- object目录: 数据库的所有内容
- refs目录: 存储 pointers which 指向提交对象. ??这个描述后面改下.
后续内容, 介绍着4个条目.
1.1.2 Git 对象
Git is a content-addressable filesystem, 意思是: 其核心 就是一个简单的键值对数据库(key-value datastore). 插入内容会获得一个key, 用key可以找回对应数据.
在Git中插入, 就是:
- 得到key key 是个 SHA-1值(40位), 该值由 数据内容+header 计算得到.
- 在objects目录下, 生产key相关的文件 以key(key共40位)的头2位为目录, 后38位为文件名
例如:
$ echo ‘test content‘ | git hash-object -w --stdin d670460b4b4aece5915caf5c68d12f560a9fe3e4 $ echo ‘version 2‘ > test.txt $ git hash-object -w test.txt 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
在Git中获取, 就是:
- 利用key获取内容
$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4 test content
目前剩下的问题是:
- 不可能人工管理key, 记版本的key.
- 存数据时, 没有存文件名.
- 数据对象
数据对象(blob object) 对应实际的数据. 前面实例中的都是数据对象.
- 树对象
树对象(tree object), 可以:
- 解决文件名保存问题
- 将多个文件组织到一起
所有内容 均以 树对象和数据对象的形式存储, 类似UNIX文件系统:
- 树对象 对应 UNIX中的目录项 一个树对象 包含: 多条 树记录(tree entry) 每条树记录 包含: SHA-1指针(指向其他数据对象或树对象), 文件名 等.
- 数据对象 对应 inodes或文件内容
树对象从 暂存区(staging area) 生成. 因此, 生成新的树对象, 首先要添加到 暂存区.
$ git update-index --add --cacheinfo 100644 83baae61804e65cc73a7201a7252750c76066a30 test.txt $ echo ‘new file‘ > new.txt $ git update-index --add new.txt
- 提交对象
目前问题: 能创建快照, 但是没有其他信息保存, 且只能记住SHA-1值. 提交对象(commit object)用于保存这些信息. commit 对象指向了顶层 tree 对象以及先前的 commit 对象.
1.1.3 Git References
问题: 需要记住提交的SHA-1
references(引用): 通过简单的名字记录SHA-1值. 在refs目录下的文件, 文件记录了提交的SHA-1.
git branch 创建分支, 就是 用当前分支的 最后一次SHA-1, 创建引用.
1.2 Git 分支
1.2.1 何谓分支
Git分支: 本质上仅仅是指向 提交对象 的指针.*
git branch <new_branch_name> 基于当前 HEAD 新建一个分支指针. HEAD是正在工作的分支的别名
1.2.2 分支的新建与合并
git checkout -b <new_branch_name> 新建并切换到分支
git merge hotfix 将hotfix代码, 合入当前分支.
分支合并, 三方合并. 找出共同祖先. 合并为一个新的 commit, 该commit有2个祖先.
git add 将把冲突文件标记为已解决.
1.2.3 分支管理
git branch -v 所有分支的最后一次提交.
git branch -a 本地和远程的所有分支.
git branch –merged git branch –no-merged
1.2.4 远程分支
远程分支(remote branch): 对远程仓库的分支的引用, 与远程仓库交互时自动移动.
git push origin <local_branch_name>:<remote_branch_name> git push origin <branch_name> 如果本地与远程分支名相同, 可以使用第二个push git push origin :<remote_branch_name> 删除远程分支
git fetch orgin 会将所有远程分支下载到本地, 但是本地不能编辑. git checkout -b <new_branch_name> origin/<remote_branch_name> 将创建可编辑的本地分支. 并且该分支是 跟踪分支.
跟踪分支(tracking branch) pull, push时, 知道关联的远程分支
1.2.5 变基
rebase(变基): 将一个分支上的改动 在另一个分支上 重做一遍. 变基的内部步骤:
- 找到基线分支, 即共同祖先;
- 提取出当前分支,即变基分支的改动
- 然后将改动应用到目标分支的最后一个提交上,
- 最后在目标分支上生成一系列新的commit, 且变基分支指向该提交.
此时, merge 目标分支 与 变基分支 就只需要快速合并了.
例如: 将 experiment rebase master上
- git checkout experiment 切到变基分支
- git rebase master rebase到目标分支
- git checkout master 切换到目标分支
- git merge experiment 快速合并