Git初探

[TOC]
Git是一个开源的分布式版本控制软件。

背景

  • 2002 年之前:Linux 内核维护工作的绝大部分时间都浪费在提交补丁与保存归档等繁琐事务上。
  • 2005 年,迫于无奈,Linus Torvalds 自行开发了一套开源版本控制工具,并命名为 Git。

自诞生以来,Git 就以其开源、简单、快捷、分布式、高效等特点,应付了类似 Linux 内核源代码等各种复杂的项目开发需求。如今,Git 已经非常成熟,被广泛接受与使用,越来越多的项目都迁移到 Git 仓库中进行管理。

一、Why Git?

实际上,相对于 CVS、SVN 等主流版本控制软件,Git的学习成本甚至会更高。比如,对于 Subversion 用户而言,如果能理解什么是文件、工作目录、资源库、版本、分支和标签等概念,差不多就够用了。而对于 Git 用户,需要理解更多更复杂的概念,包括文件、快照、工作树、索引、本地资源库、远程资源库、远程、提交、分支和 Stash 等。那么,为什么软件开发者对 Git 还是趋之若鹜呢?相比于 CVS 与 SVN,Git 的优势到底体现在哪里?

关于 Git 的各种优势,互联网以及各种 Git 书籍都给出了自己的答案。笔者认为,存储快照与分布式的设计思想是 Git 的 2 大看点,理由如下:

第一,Git 底层自行维护的存储文件系统是一大亮点。CVS、SVN 底层采用的为增量式文件系统,如图 1 所示。增量式文件系统的特点是:当文件变动发生提交时,该文件系统存储的是文件的差异信息。

图 1. CVS、SVN 记录文件内容差异
CVS、SVN 记录文件内容差异

同样是文件变更提交,Git 底层文件系统存储的则为文件快照,即整个文件内容,并保存指向快照的索引,如图 2 所示。考虑到性能因素,如果文件内容没有发生任何变化,该文件系统则不会重复保存文件,只是简单地保存文件的链接。

图 2. Git 记录整个文件快照

Git 之所以选择这样的底层存储数据结构,主要是为了提高 Git 分支的使用效率。实际上,Git 分支本质上是一个指向索引对象的可变指针,而每一个索引对象又指向文件快照,如图 3 所示。

图 3. Git 分支对应的数据结构

这样一来,创建分支可以瞬间完成,几乎不需要花费太多代价。换句话说,Git 分支是廉价的、轻量级的。我们看看各种 CVS、SVN 项目,分支通常意味着源代码的完整拷贝,其代价是昂贵的、重量级的。而对于大型项目来说,创建各种分支又是十分必要的,这与 Git 鼓励频繁创建与合并分支的理念相吻合。

第二,Git 版本控制系统的设计思想是”去中心化”。传统的 CVS 、SVN 等工具采用的是 C/S 架构,只有一个中心代码仓库,位于服务器端。而一旦由于服务器系统宕机、网络不通等各种原因造成中心仓库不可用,整个 CVS 、SVN 系统的代码检入与检出就瘫痪了。即便考虑到高可用性,通过迁移另一个中心仓库继续代码提交操作,相应的运营维护成本也会随之上升。

为了摆脱对中心仓库的依赖,Git 的初始设计目标之一就是分布式控制管理。我们给出一个样例,如图 4 所示。假如我们成立一个项目组,开发者主要由 Alice、Bob、Clair、David 四名成员组成。其中,除了中心仓库 origin(Git 默认远程仓库名称)之外,每一名成员各自负责一个本地仓库。从分布式的观点来看,David 可看成是 Alice 的远程仓库,反过来也是一样。Git 分布式的设计理念有助于减少对中心仓库的依赖,从而有效降低中心仓库的负载,改善代码提交的灵活性。

图 4. Git 分布式工作示意图

Git 分布式设计思想所带来的另外一大好处是支持离线工作。离线工作的好处不言而喻,对于 CVS、SVN 这种严重依赖网络的 C/S 工具而言,没有了网络或者 VPN ,就意味着失去了左膀右臂,代码检入与检出操作就无法正常进行。而一旦使用 Git ,即便在没有 WIFI 的飞机或者火车上,照样可以频繁地提交代码,只不过先提交到本地仓库,等到了网络连通的时候,再上传到远程的镜像仓库。

工欲善其事,必先利其器。在理解 Git 灵活的快照存储与分布式设计理念之后,我们介绍 Git 针对不同操作系统的安装过程。需要指出的是,这里仅仅粗线条地介绍 Git 的安装方法, 至于 Git 安装前提条件、安装过程出现的问题诊断等更加详细的内容描述,均不在本文的讨论范围。

各个主流版本管理工具区分

特征 CVS Git Mercurial Subversion
是否原子提交 CVS:❌ Git: ✅ Mercurial:✅ Subversion:✅
文件和目录是否可以移动或重命名 CVS: ❌ Git: ✅ Mercurial: ✅ Subversion: ✅
在移动或重命名之后智能合并 CVS: ❌ Git: ❌ Mercurial: ✅ Subversion: ❌
文件和目录拷贝 CVS: ❌ Git: ❌ Mercurtial: ✅ Subversion: ✅
远程存储仓库的备份 CVS: ⛔ 使用插件实现 Git: ✅ Mercurial: ✅ Subversion: ⛔ 插件实现
是否传递变更到父仓库 CVS: ❌ Git: ✅ Mercurtial: ✅ Subversion: ⛔ 插件实现
仓库权限 CVS: ⛔很有限 Git: ✅ Mercutial: ✅ Subversion: ✅
变更集 CVS: ❌ Git: ✅ Mercurial: ✅ Subversion: ⛔部分支持
能够只在仓库的单目录下作用 CVS: ✅ Git: ❌ Subversion: ✅
跟踪未提交的变化 CVS: ✅ Git: ✅ Mercurial: ✅ Subversion: ✅
基于单个文件的提交信息 CVS: ❌ Git: ✅ Mercurial: ❌ Subversion: ❌

>> 更多对比项

git各个版本对比

二、入门

2.1 安装git

2.1.1 window下安装

  • git-scm: 有cmd支持,及简陋的gui支持
  • TortoiseGit: windows下git gui工具,TortoiseSVN风格

2.1.2 linux下安装Git

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
###### 简单粗暴用包管理工具安装
yum install git
apt-get install git-core # for ubuntu
###### 编译安装
yum install gettext curl curl-devel zlib-devel openssl-devel perl cpio expat-devel gettext-devel -y
yum -y install zlib-devel curl-devel openssl-devel perl cpio expat-devel gettext-devel openssl zlib autoconf tk perl-ExtUtils-MakeMaker
wget https://github.com/git/git/archive/v2.11.0.tar.gz
tar xzvf v2.11.0.tar.gz
cd git-2.11.0
autoconf
./configure
make
sudo make install
cd ../
rm -rf v2.11.0.tar.gz git-2.11.0
git --version

2.1.3 mac下安装git

  • idea/phpstrom/webstrom: git扩展
  • brew install git

其他安装可以在eclipse或者idea中安装对应的git插件,另外推荐vscode - 原生支持git的文本编辑器!

2.2 git配置

git有2个配置,一个是全局配置,一个是项目配置。在git中修改配置是通过命令git config来进行配置的,如果需要配置全局的参数,需要带上 --globa参数,如git config --global user.name='xxoo'

  • ~/.gitconfig: 这是 Git 存储全局配置选项的地方。你可以通过 ~/.gitconfig 文件来做大量的事,包括定义别名、永久性打开(或关闭)特定命令选项,以及修改 Git 工作方式(例如,git diff 使用哪个 diff 算法,或者默认使用什么类型的合并策略)。你甚至可以根据仓库的路径有条件地包含其他配置文件!所有细节请参阅 man git-config, 默认的,刚安装好的git需要配置用户和邮箱:

    git config –global user.name=’your name’
    git config –global user.email=’yourmail@mail.com’

  • .git/config:这里是指项目下的.git/config文件,项目的config配置都将存储在这个文件中。.git目录简要说明:

子目录名 简要描述
branches Git 项目分支信息,新版 Git 已经不再使用该目录。
config Git 项目配置信息
description Git 项目描述信息
HEAD 指向 Git 项目当前分支的头指针
hooks 默认的”hooks”脚本,被特定事件发生前后触发。
info 里面含一个 exclude 文件,指 Git 项目要忽略的文件。
objects Git 的数据对象,包括:commits, trees, blobs, tags。
refs 指向所有 Git 项目分支的指针

常用全局配置范例

1
2
3
4
git config --global user.name "your username"
git config --global user.email "your email address"
git config --global core.autocrlf true
git config --global core.safecrlf true

2.3 git基础命令

  • git status: 查看git状态,类似于svn 的 svn status
  • git clone: 克隆源码,类似于svn 的 svn checkout
  • git add: 将文件添加到缓冲区
  • git commit : 提交文件到版本
  • git push: 推送版本到远程仓库
  • git checkout: 恢复修改的文件
  • git mv|rm: 迁移或删除文件

2.4 深入浅出git核心概念

Git 对象模型

Git对象模型是Git设计思想中最核心的部分,理解 Git对象模型是理解整个 Git 的关键。每个 Git 对象包含三部分:类型,大小和内容。其中,对象的类型又分为 commits, trees, blobs, tags,其简要说明如下:

  • blob 对象:一块二进制数据,用来存储文件数据,通常是一个文件。
  • tree 对象:指向 blob 对象或是其它 tree 对象的指针,一般用来表示内容之间的目录层次关系。
  • commit 对象:一个 commit 对象只指向一个 tree 对象,用来标记项目某一个特定时间点的状态,如时间戳、父对象、作者、提交者等。
  • tag 对象:与 CVS、SVN 标签的概念类似。

Git 三种状态

Git 仓库模型大致分为三个工作区域,分别为工作目录(Working Directory),暂存区域(Stage 或 Index),以及本地仓库(History),相应的检入与检出命令如图:

  • git add files:把当前工作文件拷贝到暂存区域。
  • git commit:在暂存区域生成文件快照并提交到本地仓库。
  • git reset – files:用来撤销最后一次 git add files,也可以用 git reset 撤销所有暂存区域文件。
  • git checkout – files:把文件从暂存区域覆盖到工作目录,用来丢弃本地修改。

Git 三种状态之间的转换

Git 分支模型

三、工具

  • Cmder:window下terminal工具
  • iTerm: mac下terminal工具
  • git-scm

课前准备

  1. GIT-SCM:https://git-scm.com/downloads
  2. cmder (window用户cmd替代工具):https://github.com/cmderdev/cmder/releases
  3. homebrew(Mac用户terminal工具):https://brew.sh/
  4. TortoiseGit(Win用户Git-GUI工具):https://tortoisegit.org/download/

四、实战

4.1 svn-git互转

4.2 分支提交、合并

总结

本次前沿部分主要给大家分享git入门相关的基础原因、基础命令的使用以及git跟svn的差异,在后续很多前沿项目中都有可能会用到此工具,希望大家能通过这次分享理解git的原理及基础的用法。

扩展&参考

emoji: