背景
版本管理的演变
VCS(Version Control System)出现之前
- 用目录拷贝区别不同版本
- 公共文件容易被覆盖
- 成员沟通成本高,代码集成效率低下
集中式 VCS(如 CVS)
- 有集中的版本管理服务器
- 具备文件版本管理和分支管理能力
- 集成效率有明显提高
- 客户端必须时刻与服务器相连
分布式 VCS(如 Git)
- 服务端和客户端都有完整的版本库
- 脱离服务端,客户端也可以管理版本
- 支持查看历史和版本比较等多数操作,都不需要访问服务器,比集中式 VCS 更能提高版本管理效率
Git
Git 是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。
Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。
Torvalds 开始着手开发 Git 是为了作为一种过渡方案来替代 BitKeeper特点
- 最优的存储能力
- 非凡的性能
- 开源
- 容易做备份
- 支持离线操作
- 容易定制工作流程
Git 安装与最小配置
安装
安装 Git
最小配置
配置 user 信息 user.name
和 user.email
$ git config --global user.name "your_name" |
config
的三个作用域,缺省等同于 local
$ git config --local # local 即只针对某个仓库有效 |
显示 config
的配置, 加 --list
参数
$ git config --list --local |
创建 Git 仓库
分为以下两种场景:
- 把已有的项目代码纳入 Git 管理
$ cd 项目代码所在的目录
$ git init - 新项目直接使用 Git 管理
$ cd 某个目录
$ git init your_project # 该命令会在该目录下创建与项目名称同名的目录
$ cd your_project
基本使用与常用命令
认识工作区与暂存区
以下为一些常用的基本命令:
$ git status # 查看工作目录与暂存区的状态 |
常用命令介绍
文件重命名
git mv old_name new_name
回退到上一次 commit
git reset --hard
通过 git log
查看版本演变历史
- 查看当前分支的 commit 历史信息
git log
不加任何参数时只查看当前分支 - 查看所有分支的 commit 历史信息
git log --all
- 图形化(字符画)展示 commit 历史信息
git log --all --graph
- 查看历史 commit 信息列表(简洁信息)
git log --oneline
- 查看最近的 4 条历史 commit 信息列表
git log -n4 --oneline
- 图形化界面工具,查看所有分支的 commit 历史信息
gitk --all
查看分支
- 查看当前分支
git branch
- 查看本地所有分支信息
git branch -v
- 查看所有分支信息(包含远程分支)
git branch -av
管理分支
- 创建新分支
git checkout -b 新分支名称 hash值
填写 commit 的 “hash值” 可以指定基于该 commit 创建新分支(可用git log
命令查看对应 commit 的 “hash值” ) - 切换分支
git checkout 其他已存在的分支
Git 原理剖析
首先进入 .git
目录下,接下来对 .git
目录下的各文件与目录进行解析
HEAD 文件
$ cd .git/ |
即 HEAD
文件中的内容为 ref: refs/heads/master,那么这个内容代表什么意思呢?
此时输入 git branch -av
显示我们当前所在分支为 * master
, *
即代表当前所在,由此我们了解了,HEAD
文件中的内容即是记录了我们当前所在的分支信息。而 refs/heads/master
看起来像是一个路径,这个接下来再说
config 文件
$ cd .git/ |
显而易见 .git
目录下的 config
文件中保存了 --local
相关信息,此时修改文件中的内容后使用 git config --local --list
命令查看相应结果也会发生对应的变化
refs 目录
$ cd .git/ |
heads 目录
小技巧:
git cat-file -t 2b81da
该命令可以查看以上对象2b81da
(这里它本应该表现为一个完整的 hash 值,截取其名称前 5-6 个字符或更多字符即可代表该对象)的类型
$ cd heads/ |
接着上面 HEAD
文件没有说完的内容,refs/heads/master
看起来像是一个路径,由此我们进入这个路径进行探寻
对于 .git/refs/heads/master 文件
,其中存放的是当前 master
分支指针指向的 commit
注释:refs 目录下的 heads 目录可以理解为存放当前分支的目录
tags 目录可以理解为存放该仓库所有标签的目录,标签一般意味着一段开发历程的里程碑
tags 目录
接上,下面再来看一下 tags
路径下有什么
小技巧:
git cat-file -p 345864
该命令查看以上对象345864
的内容
$ cd .git |
注释:当我们查看 tags 路径下文件的内容时,显示了一个 hash 值,它通常代表一个对象,接着我们查看它的类型 —— 一个 tag 类型;接着是它的内容,内容中又包含一个 hash 值,它已经标注了自己的类型 —— 是一个 commit,并且还包含了 tag 名称、生成时间戳、提交人信息、commit message 等,可以再使用命令
git cat-file -t f6237a
检查一下
Git 文件系统的核心 - objects
$ cd .git |
注释:当我们进入 objects 目录下时使用
ll -a
命令可以看到一些以两个字母命名的目录。
随机选择进入一个这样的目录后再使用ll -a
命令,得到的将是一个或多个类似 hash 值命名的对象,实际上 Git 的策略是以它的父级目录名加上该类似 hash 值的内容拼接作为一个 hash 值,查看该对象的类型,其为一个新的类型 —— tree,接着查看它的内容,其中又包含一个新类型 blob,代表文件类型,查看这个 blob 类型对象的内容即为实际文件的内容(即 file_name 对应的文件)
实际上,只要任何文件的内容是相同的,那么在 Git 看来它就是唯一的一个 blob
Git 对象彼此关系
- 一个 commit 对应一个 tree,它代表了这个 commit 在这个时间点整个仓库的快照,即在这个时间点:目录结构、文件是什么样子,将通过 tree 呈现出来 —— 见黄色部分 823gb7…
- tree 代表文件夹,tree 中可以包含 tree
- 可以看到 tree - 87a87a 代表 images 文件夹,具体见箭头指向
- 可以看到 tree - bdd489 代表 styles 文件见,具体见箭头指向
- blob 代表文件,blob 与文件名没有任何关系,即不管文件名为什么,文件内容相同那么就只有一个 blob