git对象模型
刚接触git版本库的时候,我就非常好奇,它是如何做版本控制的?版本库大小为什么又没有膨胀?它究竟是如何工作的呢?
git 中的每一个对象都包含类型、大小、和内容。大小就是内容的大小,内容取决于对象类型。git对象有以下四种:blob、tree、commit和tag。
-
blob类型
blob类型用来存储数据,也就是文件的内容,它是一个二进制块。
-
tree类型
tree就来管理blob对象和其他tree对象。可以把tree对象看成目录,它管理子目录和文件
commit类型
一个commit仅指向一个tree。它标记某个时间点上git的状态。它包含一些元数据比如:上次提交的时间戳,最近一次提交的作者,以及执行最近一次提交的指针等。-
tag类型
tag是标记某一次提交的方法。
-
commit、tree、blob是如何组合在一起的呢?
例如如下的目录结构:
|-->root
|---->README
|---->lib
|-------->inc
|------------>tricks.rb
|-------->mylib.rbgit中的对象图大概就是如下的样子:
对象名
这些对象的名称都是根据其内容通过SHA1算法计算出来的,与文件所在路径、作者、创建时间等信息都无关, 也就是说如果两个文件内容完全一样,那么它任何时间计算出来的对象名都是一样的。
Git仓库结构
- 工作区【Working Directory】
简单理解的说,git仓库所在的目录就是工作区,除了里面一个.git的隐藏文件夹。 - 版本库【Repository】
在工作区中提到的隐藏文件夹就是版本库。当我们初始化一个git版本库的时候,其中了很多东西,包括第一个分支master,以及指向分支master的指针head。 - 暂存区【Stage/Index】
版本库中一个很重要的区域,就是暂存区, 当我们把一个文件加入到版本库(git add filename)这个文件首先是被加入的暂存区的,直到进行了一次提交(git commit)。
无论是暂存区还是真正的版本库,其中保存的都是git对象模型中提到的那四种类型, 当一个修改在这几个区域变化的时候,只是各种区域的指针指向了这个文件,所以它是非常迅速的,因为仅仅是做了指针操作。
Git基本命令
- 配置Git
git.config --global user.name "username"
git.config --global user.email "username@git.com"
git.config --global core.autocrlf false
git.config --global core.safecrlf true - 生成SSH配置
ssh -keygen -t rsa -C "username@git.com" - copy SSH key
clip < ~/.ssh/id_rsa.pub - 将SSH KEY配置到git@trgit2上后,测试连接
ssh -T git@trgit2 - 初始化Git仓库, 有两种方式:
- 直接clone远程仓库
git clone xxx.git - 现有本地仓库
git init
git remote add origin xxx.git
git push -u origin master
- 直接clone远程仓库
- 提交修改
git add --all
git commit -m "xxx"
add: 将修改从工作提交到暂存区
commit:将修改从暂存区提交到版本库 - 回滚修改
- 从版本库回滚到某次提交:
git reset --hard [commentid] - 丢弃工作区中某文件的修改:
git checkout --filename
- 从版本库回滚到某次提交:
- 提交到远程分支
git push origin master
git push origin dev:dev - 创建分支
git checkout -b dev - 合并分支
git merge dev
最好加上--no-ff参数,强制不进行快进式合并,这个样可以保证合并会产生一个合并commit,这样可以很直观地看出合并历史。
git分支模型
现在的软件工程早已过了曾经那个充满个人英雄主义色彩的时代,我们的大多数项目都是多人协同开发出来的。那多人究竟应该如何协作才能保证版本管理不混乱呢?git为我们提供了一个fork的功能。
- 何为Fork?
一个fork就是一个repository的拷贝。fork让我们可以改变repository的内容,让版本独自进行演进。但这并不会使源repository受到影响。我们可以从源repositoryfetch
更新,然后merge
到自己的仓库,我们也可以把自己的变笨pull request
到源repository。 - 需要用到的git命令
- 查看关联的remote repository url
git remote -v
origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (fetch)
origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (push) - 使用upstream来指定我们fork的responsitory来实现同步。
git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git - 验证是否添加成功
git remote -v
origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (fetch)
origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (push)
upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git (fetch)
upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git (push) - 获取upstream repository上的commits
git fetch upstream
remote: Counting objects: 75, done.
remote: Compressing objects: 100% (53/53), done.
remote: Total 62 (delta 27), reused 44 (delta 9)
Unpacking objects: 100% (62/62), done.
From https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY
* [new branch] master -> upstream/master - 切换到自己的fork上local master分支
git checkout master - 合并upstream/master的更新到local master
git merge upstream/master
- 查看关联的remote repository url