1 什么是git

1.1 简介

GIT是一种分布式版本控制系统,通俗点说版本控制就是当文档写错了,能够让你回退到之前某个正确的版本,给你一着悔棋。

1.2 版本控制系统
1.2.1 本地版本控制系统

许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间进行区别。这么做的唯一好处就是简单,坏处也不少:有时候会混淆所在的工作目录,一旦弄错了文件数据就没办法撤销恢复。为了解决这个问题,人们很久以前就开发了许多本地版本控制系统,大多是采用某种简单的数据库来记录文件的历次更新差异。

1.2.2 集中式版本控制系统

接下来人们又遇到一个问题,如何让在不同系统上的开发者协同工作?于是,集中化的版本控制系统(Centralized Version Control Systems)应运而生。这类系统,诸如CVS、Subversion等,都有一个单一的集中管理服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。多年以来,这已成为版本控制系统的标准做法。

这么做带来了很多好处,特别是相对于本地版本控制系统来说。现在,每个人都可以在一定程度上看到项目中的其他人正在做什么,管理员也可以轻松掌握每个开发者的权限,看到每个人每天的提交记录。这样做最大的缺点就是中央服务器的单点故障。如果宕机一小时,那么在一小时内所有人都无法提交更新,也就无法协同工作。要是中央服务器的磁盘发生故障,碰巧没有备份或者备份不及时,就会有丢失数据的风险。最坏的情况是彻底丢失整个项目的所有历史更改记录,而被客户端提取出来的某些快照数据除外,但是不能够保证所有的数据都已经有人事先完整的提取出来。

本地版本控制系统也存在类似问题,只要整个项目的历史记录被保存在单一位置,就有丢失所有历史更新记录的风险。

1.2.3 分布式版本控制系统

分布式版本管理系统就是为了解决这个单点问题,在这类系统中,像Git、Mercurial、Bazaar以及Darcs等,客户端并不只是提取最新的文件快照,而是把原始的代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份。更进一步,这类系统都可以指定和若干不同的远端代码仓库进行交互。因此,你就可以在同一个项目中,分别和不同工作小组的人相互协作。你可以根据需要设定不同的协作流程。

1.3 Git与SVN等常规版本控制软件的区别
1.3.1 直接记录快照,而非差异比较

Git和其他版本控制系统的主要差别在于,Git只关心文件数据的整体是否发生变化,而大多数其他系统则只关心文件内容的具体差异。这类系统(CVS、Subversion等)每次记录都有哪些文件做了更新,以及更新了哪些行的什么内容,如下图:

这里写图片描述

Git 并不保存这些前后变化的差异数据。实际上,Git 更像是把变化的文件作快照后,记录在一个微型的文件系统中。每次提交更新时,它会纵览一遍所有文件的指纹信息并对文件作一快照,然后保存一个指向这次快照 的索引。为提高性能,若文件没有变化,Git 不会再次保存,而只对上次保存的快照作一链接。Git 的工作方式就像下图所示:

这里写图片描述

这是 Git 同其他系统的重要区别。它完全颠覆了传统版本控制的套路,并对各个环节的实现方式作了新的设计。Git 更像是个小型的文件系统,但它同时还提供了许多以此为基础的超强工具,而不只是一个简单的 VCS。

1.3.2 支持离线工作(近乎所有操作都是本地执行),本地提交可以稍后提交到服务器上;
1.3.3 时刻保持数据完整性;
1.3.4 多数操作仅添加数据;

2 git的组成

每个GIT工程的三个组成部分: git目录(Git Directory),工作目录(Working Directory),以及暂存区(stage area)。

2.1 Git目录(Git Directory)(HEAD)

Git目录是GIT里面最重要的一部分,文件夹名字为“.git”。你从服务器clone一个项目的时候,其实就是clone一个 “.git”的文件夹!

Git目录里面包括了所有的元数据:当前分支,所有本地分支,remote信息,配置文件等等,另外最重要也是最大的就是所有的GIT对象,这些GIT对象记录了所有的历史记录以及文件改动。

2.2 Git目录(Working Directory)

从GIT角度看,一个工作目录就是GIT的一个版本,里面的文件是从压缩的GIT数据库里面解压出来,然后放在你的文件系统里。从使用的角度看,我们开发时用到的所有文件都是工作目录里面的文件。这些文件都放在项目的根目录下,跟“.git”在同一文件层次目录。

2.3 暂存区(Stage Area)

暂存区保存着下一个commit将会包含的所有改动。但实际上,暂存区只是一个文件,而不是一个文件夹。暂存区的这个文件一般叫”index”,保存在”.git”目录下。

这里写图片描述

3、git的工作流程

基本的git工作流程如下:

  1. 在工作目录中修改某些文件。

  2. 对修改后的文件进行快照,然后保存到暂存区域。

  3. 提交更新,将保存在暂存区域的文件快照永久转储到 Git 目录中。

  4. 将更改后的代码提交到远程库。

每个文件的状态不是tracked就是untracked。 track指的是该文件已经在GIT的监控范围之内了,该文件的每一点改动GIT都能跟踪到;untrack指的是该文件不在GIT的监控范围之内,它的改动GIT是不会去跟踪的。
而每个tracked的文件将会处于如下四种状态的其中一种:unmodified,modified,staged, committed。

如果是 Git 目录中保存着的特定版本文件,就属于已提交状态(committed);如果作了修改并已放入暂存区域,就属于已暂存状态(staged);如果自上次取出后,作了修改但还没有放到暂存区域,就是已修改状态(modified)。

  • unmodified说的就是这个文件木有动过
  • modified是指你的文件已经改动了,但是还没有保存到你的本地数据库里面;
  • staged是指你的文件改动了,并且添加到暂存区里面,下次提交就会把这些改动保存到本地数据库;
  • committed是指你的文件改动了,并且已经保存到本地数据库

每个真正进入版本库的文件都需要按照这种顺序执行:modified -> staged -> committed。同时这三种状态是互斥的,也就是说一个文件只能同时处于其中的一种状态而已!

举个栗子:

先对文件做修改:

$ echo haha >>README.md

然后查看状态:

$ git status

On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

从上面得到信息,GIT跟踪到文件README.md已经处于modified的状态了,但是并没有加入到暂存区(Changes not staged for commit)。

然后将文件加入到暂存区:

$ git add README.md

如果在执行add操作时出现warning: LF will be replaced by CRLF in README.md设置git config core.autocrlf false即可解决。或是放任不管也没关系。

再来观察状态:

$ git status

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   README.md

GIT的信息说明了README.md的改动已经在暂存区里面了,下一步的工作就是使用commit就文件变动存入到本地数据库中继而将文件push到远程库中。

做一个比喻:文件修改就好比是商品,暂存区就好比是购物车。当我们修改好文件(选好商品)之后,通过 git add命令(拿起商品放到)放到暂存区 (购物车),然后通过commit(买单)将改动加到代码库(将商品拿回家里去)。当然,在这个过程当中,暂存区的文件是可以再回到工作区的(把商品放回货架上)。

参考
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐