前言
Git 是一个免费并且开源的分布式版本控制系统,旨在快速高效地处理从小到大所有项目的版本管理。Git 是目前最流行的版本管理工具,目前绝大部分公司都是使用 Git 作为项目的版本管理工具。目前最火的开源社区 Github,就是基于 Git 版本控制系统,所以掌握 Git 技能很重要。由于 Git 开发效率高、团队协作方便,现在很多 IDE 都集成了 Git,并且提供一些相关的图形化操作。也有很多很优秀,专门用来简化 Git 操作的 Git GUI 工具,例如 Sourcetree,Tortoise 等。我刚接触 Git 的时候,就是从 GUI 入手的,使用 Sourcetree 可视化版本控制工具进行操作。Sourcetree 底层也是对常用的 Git 命令进行封装实现的,傻瓜式操作,使用非常方便,但是我用完什么都不懂,Git 的内部原理也不易理解,决定在回头仔细学习一下 Git 命令行。学习完 Git 命令行后发现,命令行很好学,非常灵活,而且使用起来非常帅气。因此,直接 Git 命令,才是最灵活的操作。
本篇是我学习 Git 系列的开篇,主要讲述 Git 的基本概念和工作原理,然后介绍一下 Git 安装以及环境配置,最后探讨一下 Git 常用命令以及使用场景。
Git 基本概念以及工作原理
你所不了解的 Git 诞生史
同生活中的许多伟大事件一样,Git 诞生于一个极富纷争大举创新的年代。众所周知,Linux 内核开源项目有着为数众广的参与者,但是绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002 年间),即 Linus 本人通过手工方式合并世界各地志愿者通过 diff 的方式传过来的代码。
到 2002 年后,由于代码库太大,Linus 很难继续通过手工方式进行管理,于是 Linux 整个项目组开始启用分布式版本控制系统 BitKeeper 来管理和维护代码,BitKeeper 的东家 BitMover 公司出于人道主义精神,授权 Linux 社区免费使用这个版本控制系统。
到了 2005 年,一位 Linux 开发成员 Andrew(Samba 协议之父)写了一个可以连接 BitKeeper 仓库的外挂,因此 BitMover 公司(BitKeeper 持有者)认为他反编译了 BitKeeper;于是 BitMover 决定中止 Linux 免费使用 BitKeeper 的授权。最终 Linux 团队与 BitMover 磋商无果,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了免费使用 BitKeeper 的权力。这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)不得不吸取教训,只有开发一套属于自己的版本控制系统才不至于重蹈覆辙。
于是,Linus 花了两周时间用 C 语言写了一个分布式版本控制系统,这就是 Git!一个月之内,Linux 系统的源码已经由 Git 进行管理了!
Git 工作原理
Git 是一套内容寻址文件系统,Git 从核心上来看不过是简单地存储键值对(key-value)。它允许插入任意类型的内容,并会返回一个键值,通过该键值可以在任何时候再取出该内容。可以通过底层命令 hash-object 来示范这点,传一些数据给该命令,它会将数据保存在 .git 目录并返回表示这些数据的键值。
文件目录
Git 工作区有个隐藏目录. git,核心文件包括:config 文件、objects 文件夹、HEAD 文件、index 文件以及 refs 文件夹。下面依次对其进行说明:
- config 文件:该文件主要记录针对该项目的一些配置信息,例如是否以 bare 方式初始化、remote 的信息等,通过 git remote add 命令增加的远程分支的信息就保存在这里;
- objects 文件夹:该文件夹主要包含 git 对象。Git 中的文件和一些操作都会以 git 对象来保存,git 对象分为 BLOB、tree 和 commit 三种类型,例如 git commit 便是 git 中的 commit 对象,而各个版本之间是通过版本树来组织的,比如当前的 HEAD 会指向某个 commit 对象,而该 commit 对象又会指向几个 BLOB 对象或者 tree 对象。objects 文件夹中会包含很多的子文件夹,其中 Git 对象保存在以其 sha-1 值的前两位为子文件夹、后 38 位位文件名的文件中;除此以外,Git 为了节省存储对象所占用的磁盘空间,会定期对 Git 对象进行压缩和打包,其中 pack 文件夹用于存储打包压缩的对象,而 info 文件夹用于从打包的文件中查找 git 对象;
- HEAD 文件:该文件指明了 git branch(即当前分支)的结果,比如当前分支是 master,则该文件就会指向 master,但是并不是存储一个 master 字符串,而是分支在 refs 中的表示,例如 ref: refs/heads/master。
- index 文件:该文件保存了暂存区域的信息。该文件某种程度就是缓冲区(staging area),内容包括它指向的文件的时间戳、文件名、sha1 值等;
- Refs 文件夹:该文件夹存储指向数据(分支)的提交对象的指针。其中 heads 文件夹存储本地每一个分支最近一次 commit 的 sha-1 值(也就是 commit 对象的 sha-1 值),每个分支一个文件;remotes 文件夹则记录你最后一次和每一个远程仓库的通信,Git 会把你最后一次推送到这个 remote 的每个分支的值都记录在这个文件夹中;tag 文件夹则是分支的别名,这里不需要对其有过多的了解;
工作区域
Git 本地有三个工作区域:工作目录(Workspace)、暂存区 (Stage/Index)、资源库(Repository)。如果在加上远程的 git 仓库(Remote Directory) 就可以分为四个工作区域。文件在这四个区域之间的转换关系如下:
- Workspace:工作区,就是你平时存放项目代码的地方。
- Index / Stage:暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息。
- Repository:仓库区(或本地仓库),就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中 HEAD 指向最新放入仓库的版本。
- Remote:远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换。
工作流程
Git 的工作流程一般是这样的:
1、在工作目录中添加、修改文件;
2、将需要进行版本管理的文件放入暂存区域;
3、将暂存区域的文件提交到 Git 仓库。
Git 文件 4 种状态
- Untracked: 未跟踪, 此文件在文件夹中, 但并没有加入到 git 库, 不参与版本控制. 通过 git add 状态变为 Staged.
- Unmodify: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为 Modified. 如果使用 git rm 移出版本库, 则成为 Untracked 文件
- Modified: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过 git add 可进入暂存 staged 状态, 使用 git checkout 则丢弃修改过, 返回到 unmodify 状态, 这个 git checkout 即从库中取出文件, 覆盖当前修改
- Staged: 暂存状态. 执行 git commit 则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为 Unmodify 状态. 执行 git reset HEAD filename 取消暂存, 文件状态为 Modified
Git 安装以及环境配置
本文统一使用软件包管理器的方式安装 Git,减少环境变量的配置,更加方便快捷。
Linux 安装 Git
CentOS7 中使用 yum 安装 Git 的方法
1 | # 1. 查看 git 是否安装 |
Mac 安装 Git
Mac 中使用 brew 安装 Git 的方法
1 | # 1. 查看 git 是否安装 |
Windows 安装 Git
Windows 中使用 choco 安装 Git 的方法
1 | # 1. 查看 git 是否安装 |
全局配置
Git 用户的配置文件位于 ~/.gitconfig
Git 单个仓库的配置文件位于 ~/$PROJECT_PATH/.git/config
1 | # 1. 显示当前的 Git 配置 |
如果用了 –global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。如果要在某个特定的项目中使用其他名字或者电邮,只要去掉 –global 选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。
服务器上的 Git - 生成 SSH 公钥
大多数 Git 服务器都会选择使用 SSH 公钥来进行授权。系统中的每个用户都必须提供一个公钥用于授权,没有的话就要生成一个。SSH 公钥默认储存在账户的主目录下的 ~/.ssh 目录。
1 | 1. 进入主目录下的~/.ssh 目录 |
关于在多个操作系统上设立相同 SSH 公钥的教程,可以查阅 GitHub 上有关 SSH 公钥的向导。
Git 常用命令以及使用场景
仓库
1 | 1. 在当前目录新建一个 Git 代码库 |
增加 / 删除文件
1 | # 1. 添加指定文件到暂存区 |
代码提交
1 | # 1. 提交暂存区到仓库区 |
分支
1 | 1. 列出所有本地分支 |
标签
1 | # [1]. 列出所有 tag |
查看信息
1 | [1]. 显示有变更的文件 |
远程同步
1 | # [1]. 下载远程仓库的所有变动 p.s.[从远程 refs/heads / 命名空间复制所有分支, 并将它们存储到本地的 refs/remotes/origin / 命名空间] |
撤销
1 | # 1. 恢复暂存区的指定文件到工作区 p.s.[撤销对工作区修改: 这个命令是以最新的存储时间节点 (add 和 commit) 为参照, 覆盖工作区对应文件 file; 这个命令改变的是工作区] |
参考博文
[1]. 深入浅出 Git 教程
[2]. 常用 Git 命令清单
[3]. 图解 Git