Git工程开发实践(一)——Git基础

一、版本控制系统

1、版本控制系统简介

版本控制系统(VCS,Version Control Systems)是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。
版本控制系统分为:
A、本地版本控制系统(LVCS,Local Version Control Systems)
B、集中式版本控制系统(CVCS,Centralized Version Control Systems)
C、分布式版本控制系统(DVCS,Distributed Version Control System)

2、本地版本控制系统

本地版本控制系统大多都是采用某种简单的数据库来记录文件的历次更新差异。最流行的本地版本控制系统为RCS,其工作原理是在硬盘上保存补丁集(补丁是指文件修订前后的变化),通过应用所有的补丁,可以重新计算出各个版本的文件内容。
Git工程开发实践(一)——Git基础_第1张图片

3、集中式版本控制系统

集中式版本控制系统(CVCS,Centralized Version Control Systems )都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的开发人员都通过客户端连到服务器,取出最新的文件或者提交更新。集中式版本控制系统有CVS、Subversion、Perforce 等。
Git工程开发实践(一)——Git基础_第2张图片
集中式版本控制系统的优点:相比本地版本控制系统,每个人都可以在一定程度上看到项目中的其他人正在做些什么。管理员可以轻松掌控每个开发者的权限,并且管理一个CVCS远比在各个客户端上维护本地数据库简单。
集中式版本控制系统的缺点:中央服务器的单点故障。如果中央服务器宕机,开发人员无法提交更新,无法协同工作。如果中央服务器的数据库所在磁盘发生损坏并且没有备份,将导致数据丢失。

4、分布式版本控制系统

分布式版本控制系统(DVCS,Distributed Version Control System )中,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来,因此,任何一处协同工作用的服务器发生故障,都可以用任何一个镜像出来的本地仓库恢复。分布式版本控制系统的每一次的克隆操作都是一次对代码仓库的完整备份。
常见的分布式版本控制系统有Git、Mercurial、Darcs、Bazaar等。
Git工程开发实践(一)——Git基础_第3张图片
分布式版本控制系统的特点是分布式,每一个节点都拥有仓库的完整镜像,每个节点都可以作为服务器,也可以作为客户端。为了团队协同开发进行分支合并,通常会将一个节点设置成伪中央服务器
分布式版本控制系统的优点:
A、提交分支不需要联网,客户端本地保存着所有历史记录。
B、不依赖服务器的稳定性,风险分散。
分布式版本控制系统的缺点:
A、同步多人的修改稍繁。
B、缺少权限管理系统。
分布式版本控制系统的适用场景:
A、开源软件的开发
B、同步需求不频繁或者异地的多人协作

二、Git基础

1、Git简史

Linux内核开源项目有广泛的参与者,但在1991-2002年间,世界各地的Linux内核开发者把源代码文件通过diff的方式发给Linus,然后由Linus本人通过手工方式合并代码,因此绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上。虽然Linux内核社区有很多人提议使用集中式版本控制系统对Linux内核项目进行管理,但Linus坚持拒绝使用必须联网(龟速)才能使用的集中式版本控制系统以及付费的商业版本控制系统。到2002年,BitMover授权Linux内核社区免费使用商业分布式版本控制系统BitKeeper来管理和维护代码。
2005年,BitMover公司发现活跃于Linux内核社区的Andrew(Samba开发者)试图破解BitKeeper的协议,于是收回了Linux内核社区使用BitKeeper的免费授权。 但Linux项目千万行级别的代码管理不可能再回到石器时代的手动合并,于是Linus基于使用BitKeeper的经验教训与Linux项目团队的需求,使用了两周时间开发出了Git初始版本,一个月后Git已经用于Linux内核项目源码的管理。 目前Git由Linux社区的其它开发人员在持续开发。
大部分版本控制系统,如CVS、Subversion、Perforce、Bazaar等以文件变更列表的方式存储信息。通常保存的信息是一组基本文件和每个文件随时间逐步累积的差异。
Git工程开发实践(一)——Git基础_第4张图片
Git把数据看作是对小型文件系统的一组快照。每次提交更新或在Git中保存项目状态时,主要对当时的全部文件制作一个快照并保存快照的索引。如果文件没有修改,Git不再重新存储该文件,而是只保留一个链接指向原来存储的文件。
Git工程开发实践(一)——Git基础_第5张图片

2、Git安装

Linux发行版:
Fedora:sudo yum install git
Debian:sudo apt-get install git
Windows:
https://git-scm.com/download/win
Git for Windows(msysGit)
GitHub for Windows
Mac OS:
OSX Git:http://git-scm.com/download/mac

3、Git配置

Git使用git config工具来设置控制Git外观和行为的配置变量。
git config --system
在/etc/gitconfig文件读写配置变量,包含系统上每一个用户及仓库的通用配置,对当前操作系统所有用户、仓库有效
git config --global
在~/.gitconfig 或 ~/.config/git/config文件读写配置变量,对当前用户有效
git config --local
在仓库的.git/config文件读写配置变量,针对当前仓库有效。
低级别的Git配置信息会覆盖上一级别的配置信息,所以当前仓库的配置信息(.git/config) 会覆盖 /etc/gitconfig 中的配置信息。
通常,安装完Git后需要设置用户信息,如用户名称与邮件地址。因为每一个Git提交操作都会使用Git用户信息,并且写入到每一次提交中,不可更改。

git config --global user.name "username"
git config --global user.email "[email protected]"
Git配置信息查看:git config --list
Git某项配置信息查看:git config 
删除某项配置信息:git config --global unset 

4、Git常用术语

分支(branch):在一个时间点,复制一份处于版本控制之下的文件,可以独立的互不干扰的对拷贝进行各自开发。
检出(checkout):在本地创建一份仓库的工作拷贝。
提交(commit):将本地的修改写回到仓库或合并到仓库。
冲突(conflict):当多个开发者同时提交对同一个文件的修改,而且版本控制系统不能对其进行合并,就会引发冲突,需要手动处理。
合并(merge):把所有对文件的修改统一到文件里。
仓库(repository):当前的和历史的处于版本控制下的文件所在的地方。

5、Git工作区

Git本地有三个工作区域:工作目录(Work Directory)、暂存区(Stage/Index)、本地仓库(Repository)。
工作目录:工作目录/工作空间,存放项目代码的目录
暂存区:暂存区,用于临时存放改动,本质是一个文件,保存即将提交到文件列表信息
本地仓库:安全存放提交的所有版本的数据,其中HEAD指向最新放入仓库的版本
远程仓库(Remote Repository):托管代码的服务器
Git工程开发实践(一)——Git基础_第6张图片
Directory:Git管理的工程目录,包含工作目录和Git管理空间。
Work Directory:工作目录,存放通过Git进行版本控制的目录和文件,是开发者工作的目录。
.git:存放Git管理信息的目录,初始化仓库时自动创建。
Index/Stage:暂存区,即待提交更新区,本质是一个文件(.git/index),保存有下次将提交的文件列表信息。
Repository:本地仓库,存放在本地的版本仓库。
HEAD:HEAD指针,用于指向当前分支的一个提交。
Stash:储藏,是一个工作状态保存栈,用于保存/恢复工作目录的临时状态。

6、Git工作流程

Git提交的基本工作流程如下:
A、在工作目录中添加、修改、删除文件。
B、将工作目录中需要进行版本管理的文件添加到暂存区。
C、将暂存区的文件提交到本地仓库。
Git工程开发实践(一)——Git基础_第7张图片

7、.gitignore文件过滤

工程开发中,在进行Git提交时,并不是所有的文件都需要提交,比如一些自动生成的文件,可以配置.gitignore来忽略一些不需要提交的文件。
Git对于.gitignore 配置文件是按行从上到下进行规则匹配的,如果前面的规则匹配的范围更大,则后面的规则将不会生效。
不同工程应用开发的.gitignore模板集合如下:
https://github.com/github/gitignore
.gitignore文件语法规范如下:

    A、空行或是以#开头的行即注释行将被忽略;
    B、可以在前面添加正斜杠/来避免递归;可以在后面添加正斜杠/来忽略文件夹,例如build/即忽略    build文件夹
    C、可以使用!来否定忽略;
    D、*用来匹配零个或多个字符;
    E、[]用来匹配括号内的任一字符,如[abc],也可以在括号内加连接符,如[0-9]匹配0至9的数;
    F、?用来匹配单个字符;

.gitignore示例如下:

# 忽略 .a 文件
*.a
# 但否定忽略 lib.a, 尽管已经在前面忽略了 .a 文件
!lib.a
# 仅在当前目录下忽略 TODO 文件, 但不包括子目录下的 subdir/TODO
/TODO
# 忽略 build/ 文件夹下的所有文件
build/
# 忽略 doc/notes.txt, 不包括 doc/server/arch.txt
doc/*.txt
# 忽略所有的 .pdf 文件 在 doc/ directory 下的
doc/**/*.pdf