Git 开源的分布式版本控制系统

2019-11-06

Git 开源的分布式版本控制系统

Git简单的介绍

Git中文帮助手册

Git是什么,作用于什么?

Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或大或小的项目(编写一点点程序就可以合并到master主分支上,然后测试运行它)

Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。 Git 与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必 服务器端软件支持。

Git的诞生

很多人都知道,Linus 在 1991 年创建了开源的 Linux,从此,Linux 系统不断发展,已经成为 最大的服务器系统软件了。

Linus 虽然创建了 Linux,但 Linux 的壮大是靠全世界热心的志愿者参与的,这么多人在世界各地为 Linux 编写代码,那 Linux 的代码是如何管理的呢?

事实是,在 2002 年以前,世界各地的志愿者把源代码文件通过 diff 的方式发给 Linus,然后 由 Linus 本人通过手工方式合并代码!

你也许会想,为什么 Linus 不把 Linux 代码放到版本控制系统里呢?不是有 CVS、SVN 这些免 费的版本控制系统吗?因为 Linus 坚定地反对 CVS 和 SVN,这些集中式的版本控制系统不但 速度慢,而且必须联网才能使用。有一些商用的版本控制系统,虽然比 CVS、SVN 好用,但 那是付费的,和 Linux 的开源精神不符。

不过,到了 2002 年,Linux 系统已经发展了十年了,代码库之大让 Linus 很难继续通过手工 方式管理了,社区的弟兄们也对这种方式表达了强烈不满,于是 Linus 选择了一个商业的版 本控制系统 BitKeeper,BitKeeper 的东家 BitMover 公司出于人道主义精神,授权 Linux 社区 免费使用这个版本控制系统。

安定团结的大好局面在 2005 年就被打破了,原因是 Linux 社区牛人聚集,不免沾染了一些 梁山好汉的江湖习气。开发 Samba 的 Andrew 试图破解 BitKeeper 的协议(这么干的其实也 不只他一个),被 BitMover 公司发现了(监控工作做得不错!),于是 BitMover 公司怒了,要 收回 Linux 社区的免费使用权。

Linus 可以向 BitMover 公司道个歉,保证以后严格管教弟兄们,嗯,这是不可能的。实际情 况是这样的:
Linus 花了两周时间自己用 C 写了一个分布式版本控制系统,这就是 Git!一个月之内,Linux 系统的源码已经由 Git 管理了!牛是怎么定义的呢?大家可以体会一下。
Git 迅速成为最流行的分布式版本控制系统,尤其是 2008 年,GitHub 网站上线了,它为开 源项目免费提供 Git 存储,无数开源项目开始迁移至 GitHub,包括 jQuery,PHP,Ruby 等等。 历史就是这么偶然,如果不是当年 BitMover 公司威胁 Linux 社区,可能现在我们就没有免费 而超级好用的 Git 了。

SVN是按照文件目录存储的,你在本地什么样,上传到SVN上就是什么样

Git的基础概念

Git直接记录快照,而非差异比较

Git 更像是把数据看作是对小型文件系统的一组快照。 每次你提交更新,或在 Git 中保存项目状态时,它主要对当时的全部文件制作一个快照并保存这个快照的索引。 为了高效,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。 Git 对待数据更像是一个 快照流。
image.png

Version1:里面有A,B,C三个文档。
Version2:里面A改变成了A1,C改变成C1,然后B还是指向以前,所以用虚线
下面的类似

几乎所有的操作都是本地执行

在 Git 中的绝大多数操作都只需要访问本地文件和资源,一般不需要来自网络上其它计算机的信息。 如果你习惯于所有操作都有网络延时开销的集中式版本控制系统,Git 在这方面会让你感到速度之神赐给了 Git 超凡的能量。 因为你在本地磁盘上就有项目的完整历史,所以大部分操作看起来瞬间完成。

你可以在任何地方,不管有没有网络都可以进行代码修改,修改后的代码先保存到本地的仓库,等有了网络我们在合并到远程仓库,合并到主支。

Git保证完整性

Git 中所有数据在存储前都计算校验和,然后以校验和来引用。 这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 这个功能建构在 Git 底层,是构成 Git 哲学不可或缺的部分。 若你在传送过程中丢失信息或损坏文件,Git 就能发现。

Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希)。 这是一个由 40 个十六进制字符(0-9 和 a-f)组成字符串,基于 Git 中文件的内容或目录结构计算出来。 SHA-1 哈希看起来是这样:

24b9da6552252987aa493b52f8696cd6d3b00373
Git 中使用这种哈希值的情况很多,你将经常看到这种哈希值。 实际上,Git 数据库中保存的信息都是以文件内容的哈希值来索引,而不是文件名。

基本Git工作流程

  • 工作目录中修改文件 working directory
  • 暂存文件,将文件的快照放入暂存区
  • 提交更新,找到暂存区域的文件,将快照永久性存储到Git仓库目录

从上面的Git的工作流程来看,一个文件是存放在工作目录,暂存区和本地仓库三个地方的。当我们执行add命令的时候,实际上就是给当前工作目录中更改的文件做了一个快照,然后commit的时候把这个快照推向了本地仓库,然后本地仓库里面存放的是指针和快照信息,没有更改的文件只是做了链接指向

Git和SVN的区别

1)Git是分布式的,SVN是集中式的。这是Git和其他非分布式的版本控制系统,例如SVN,CVS等,最核心的区别。(Git是每个工作人员的电脑都可以作为一个仓库,不管你有没有网络,人在哪个地方你都可以正常的工作,但是SVN他所有的代码都集中的放到一个远程仓库里,你必须能访问这个,才可以对代码进行修改提交)

2)Git把内容按元数据方式存储,而SVN是按文件目录存储(你在本地什么样,上传到SVN上就是什么样);所有的资源控制系统都是把文件的元信息隐藏在一个类似.svn,.cvs等的文件夹里

3)Git分支和SVN 的分不同:分支在 SVN 中一点不特别,就是版本库中的另外一个目录

4)Git没有一个全局的版本号。而SVN有:目前为止这是跟SVN相比 Git缺少的最大的一个特征

5)git的内容完整性要优于SVN:Git的内容存储使用的事SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏

Git的安装

在centos上安装:

[root@zsf_node1 ~]# yum -y install git
[root@zsf_node1 ~]# git --version
git version 1.8.3.1

因为yum安装的git的版本是1.8版本的比较低,我们下面介绍一种通过源码编译的方式来安装git的最新版本
Git下载地址

1)安装需要依赖的库

[root@zsf_node3 ~]#  yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc perl-ExtUtils-MakeMaker -y

2) 下载新版本的安装包

[root@zsf_node3 ~]# cd /usr/local/
[root@zsf_node3 local]# ls 
bin  etc  games  include  lib  lib64  libexec  sbin  share  src
[root@zsf_node3 local]# wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.9.4.tar.xz

3) 解压安装

[root@zsf_node3 local]# tar xf git-2.9.4.tar.xz 
[root@zsf_node3 local]# cd git-2.9.4/
[root@zsf_node3 git-2.9.4]# make prefix=/usr/local/git all
[root@zsf_node3 git-2.9.4]# make prefix=/usr/local/git install
[root@zsf_node3 git-2.9.4]# rm -rf /usr/bin/git
[root@zsf_node3 git-2.9.4]#  ln -s /usr/local/git/bin/git /usr/bin/git
[root@zsf_node3 git-2.9.4]# git --version
git version 2.9.4

4) 安装2.9.4版本的git自动化脚本

#!/bin/bash
[[ $(hostnamectl | awk '/Operating/{print $3,$4,$5}') != "CentOS Linux 7" ]] && exit 
yum install curl-devel expat-devel gettext-devel wget.x86_64 \
  openssl-devel zlib-devel gcc perl-ExtUtils-MakeMaker -y 2> /tmp/git_install_error.log 
[ $? -ne 0 ] && echo "yum install error file /tmp/git_install_error.log " && exit 1
cd /usr/local && \
wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.9.4.tar.xz && \
tar xf git-2.9.4.tar.xz && \
cd git-2.9.4/ && \
make prefix=/usr/local/git all && \
make prefix=/usr/local/git install && \
rm -rf /usr/bin/git && \
ln -s /usr/local/git/bin/git /usr/bin/git && \
git --version
read -p "please input global user_name: " UserName
{UserName:=global}
git config --global user.name "$UserName"
read -p "please input global user_email: " UserEmail
{UserEmail:=global@qq.com}
git config --global user.email "UserEmail"

Git的配置

Git的配置从上到下分三层,system/global/local,使用三个不同的参数进行设置,每个层次的配置存储在不同的位置。

1)/etc/gitconfig文件:使用你这个系统所有的用户和所有的库,所有连接上来的用户都用这个用户去提交

[root@zsf_node1 git_test]# git config --system user.name 'system'
[root@zsf_node1 git_test]# git config --system user.email 
[root@zsf_node1 etc]# cat /etc/gitconfig 
[user]
        name = system
        email = 18163201@qq.com
[root@zsf_node1 git_test]# git config --system --list 
user.name=system
user.email=18163201@qq.com

2) ~/.gitconfig 文件:用户的配置,使用–global选项使Git读或写这个特定的文件

[root@zsf_node1 git_test]# git config --global user.name 'zhangshoufu'
[root@zsf_node1 git_test]# git config --global user.email 18163201@qq.com
[root@zsf_node1 git_test]# cat ~/.gitconfig 
[user]
        name = zhangshoufu
        email = 18163201@qq.com

[root@zsf_node1 git_test]# git config --global --list 
user.name=zhangshoufu
user.email=18163201@qq.com

3)为与git目录的config文件(.git/config):无论你当前在使用的库是什么,特定指向改单一的库,每个级别重写前一个界别的值,因此在.git/config中的值覆盖了在 /etc/gitconfig中的同一个值

// 因为是仓库的用户,所以我们必须要在git的仓库里面执行这个命令,否则会报错
[root@zsf_node1 /]# git config --local user.name local
error: could not lock config file .git/config: No such file or directory
[root@zsf_node1 /]# cd /root/git_test/
[root@zsf_node1 git_test]# git config --local user.name local
[root@zsf_node1 git_test]# git config --local user.email 18163201@qq.com  
[root@zsf_node1 git_test]# cat .git/config 
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[user]
        name = local
        email = 18163201@qq.com
        
[root@zsf_node1 git_test]# git config --local --list 
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
user.name=local
user.email=18163201@qq.com

Git仓库初始化

1) 新建一个仓库

[root@zsf_node1 ~]# cd /
// 创建一个目录,后面创建git仓库使用
[root@zsf_node1 /]# mkdir /git_test
[root@zsf_node1 /]# cd /git_test/
[root@zsf_node1 git_test]# pwd
/git_test 
// 使用git init命令创建一个空仓库
[root@zsf_node1 git_test]# git init 
Initialized empty Git repository in /git_test/.git/
// 空仓库创建完成后git_test目录下会生成一个.git隐藏文件夹,仓库 默认包含一个主支,即master分支,默认操作都是在主分支master上进行的
[root@zsf_node1 git_test]# ls -a 
.  ..  .git
//我们可以理解为当一个目录下面有.git结构相同的文件,我们就认为他是git的工作区

2)解释git文件下的内容

[root@zsf_node1 git_test]# tree .git/
.git/
├── branches        //分支
├── config          //配置文件
├── description
├── HEAD
├── hooks           //存放的一些脚本
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   └── update.sample
├── info
│   └── exclude
├── objects       //实际存放内容的仓库 
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags

3)设置过滤文件
有了仓库,我们便可以下git_test文件夹下的工作区做文件增删修改工作了,但很多时候,我们只在意开发过程中的源文件,并不需要管理自动产生的其他临时文件。这个时候我们便需要一个过滤文件,在这个文件中设置过滤规则,让Git能够自动过滤那些临时文件,这个文件便是.gitignore文件

//仓库目录下创建.gitignore文件
[root@zsf_node1 git_test]# touch .gitignore
[root@zsf_node1 git_test]# vim .gitignore
[root@zsf_node1 git_test]# cat .gitignore
test.txt
/test/
*.txt
常用的通配规则:
以斜杠“/”开头表示目录 
以星号“*”通配多个字符 
以问号“?”通配单个字符 
以方括号“[]”包含单个字符的匹配列表 
以叹号“!”表示不忽略(跟踪)匹配到的文件或目录

我们这里为实验环境,不设置这个

Git 仓库基础操作

Git 的四个区域


1)工作区域:当前工作的目录,目录下面有.git这个文件夹的(Workspace 实际文件)
2)暂存区 :第一次暂存文件之后,就会在git目录下生成一个index的文件(Index/Stage/Cached它像一个结存区域,临时保存你的改动).git/index
3)本地仓库:初始化git目录下的 .git 目录
4)远程仓库:远端的存放仓库,github公共仓库 gitlub私有仓库

Git 的四种状态

单就文件改动状态层面而言,Git 区域内的文件也有 4 种状态(需要注意的是文件状态并不是与 Git区域一一对应的),这是 Git 第二个重要概念。

  1. Untracked:未跟踪,在工作目录下创建了一个文件,还没有用git管理(只会出现在工作目录)
  2. UnModified:未修改,文件已经被git管理,这个文件在本地,但是这个文件没有改变,一个文件在工作区,暂存区,本地仓库存放,这三个地方存放的这个文件都一样
  3. Staged:暂存 在工作中创建的文件,提交到暂存区就变成了这个状态
  4. Modified:已修改状态 文件已经存在本地仓库了,然后你修改了这个文件,被git管理的文件改变了

image.png

Git的三种对象

blob对象: 保存着文件的快照
树 对 象: 记录着目录结构和blob对象索引
提交对象: 包含着指向树对象的指针和所有提交信息

首次提交对象及其树结构
image.png

提交对象及其父对象
image.png

Snapshot A是第一次,然commit一次就变成Snapshot B,在commit一次句变成了Snapshot C。
后一次指针一定包含前一次指针,只有这样才能找到以前的文件
Git 的分支,其实本质上仅仅是指向提交对象的可变指针。 Git 的默认分支名字是 master。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支。 它会在每次的提交操作中自动向前移动。


标题:Git 开源的分布式版本控制系统
作者:shoufuzhang
地址:https://www.zhangshoufu.com/articles/2019/11/06/1573021825415.html
名言:The master has failed more times than the beginner has tried.
评论
发表评论