Git与Repo快速入门

时间:2022-05-04
本文章向大家介绍Git与Repo快速入门,主要内容包括版本控制、一、原始版本控制、二、本地版本控制、三、集中版本控制、四、分布式版本控制、GIT、一、获得GIT仓库、二、GIT中版本的保存、三、GIT文件操作、四、GIT分支、标签-tag、REPO、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

版本控制

版本控制是什么已不用在说了,就是记录我们对文件、目录或工程等的修改历史,方便查看更改历史,备份以便恢复以前的版本,多人协作。

一、原始版本控制

最原始的版本控制是纯手工的版本控制:修改文件,保存文件副本。有时候偷懒省事,保存副本时命名比较随意,时间长了就不知道哪个是新的,哪个是老的了,即使知道新旧,可能也不知道每个版本是什么内容,相对上一版作了什么修改了,当几个版本过去后,很可能就是下面的样子了:

二、本地版本控制

手工管理比较麻烦且混乱,所以出现了本地版本控制系统,记录文件每次的更新,可以对每个版本做一个快照,或是记录补丁文件。比如RCS。

三、集中版本控制

但是本地版本控制系统偏向于个人使用,或者多个使用的人必须要使用相同的设备,如果需要多人协作就不好办了,于是,集中化的版本控制系统( Centralized Version Control Systems,简称 CVCS )应运而生,比如Subversion,Perforce。

在CVCS中,所有的版本数据都保存在服务器上,一起工作的人从服务器上同步更新或上传自己的修改。

但是,所有的版本数据都存在服务器上,用户的本地设备就只有自己以前所同步的版本,如果不连网的话,用户就看不到历史版本,也无法切换版本验证问题,或在不同分支工作。

而且,所有数据都保存在单一的服务器上,有很大的风险这个服务器会损坏,这样就会丢失所有的数据,当然可以定期备份。

四、分布式版本控制

针对CVCS的以上缺点,出现了分布式版本控制系统( Distributed Version Control System,简称 DVCS ),如GIT,Mercurial。

DVCS不是复制指定版本的快照,而是把所有的版本信息仓库全部同步到本地,这样就可以在本地查看所有版本历史,可以离线在本地提交,只需在连网时push到相应的服务器或其他用户那里。由于每个用户那里保存的都是所有的版本数据,所以,只要有一个用户的设备没有问题就可以恢复所有的数据。

当然,这增加了本地存储空间的占用。

GIT

必须要了解GIT的原理,才能知道每个操作的意义是什么,才能更容易地理解在什么情况下用什么操作,而不是死记命令。当然,第一步是要获得一个GIT仓库。

一、获得GIT仓库

有两种获得GIT仓库的方法,一是在需要用GIT管理的项目的根目录执行:

git init

执行后可以看到,仅仅在项目目录多出了一个.git目录,关于版本等的所有信息都在这个目录里面。

另一种方式是克隆远程目录,由于是将远程服务器上的仓库完全镜像一份至本地,而不是取某一个特定版本,所以用clone而不是checkout:

git clone <url>

二、GIT中版本的保存

记录版本信息的方式主要有两种:

  1. 记录文件每个版本的快照
  2. 记录文件每个版本之间的差异

GIT采用第一种方式。像Subversion和Perforce等版本控制系统都是记录文件每个版本之间的差异,这就需要对比文件两版本之间的具体差异,但是GIT不关心文件两个版本之间的具体差别,而是关心文件的整体是否有改变,若文件被改变,在添加提交时就生成文件新版本的快照,而判断文件整体是否改变的方法就是用SHA-1算法计算文件的校验和。

GIT能正常工作完全信赖于这种SHA-1校验和,当一个文件的某一个版本被记录之后会生成这个版本的一个快照,但是一样要能引用到这个快照,GIT中对快照的引用,对每个版本的记录标识全是通过SHA-1校验和来实现的。

当一个文件被改变时,它的校验和一定会被改变(理论上存在两个文件校验和相同,但机率小到可以忽略不计),GIT就以此判断文件是否被修改,及以些记录不同版本。

在工作目录的文件可以处于不同的状态,比如说新添加了一个文件,GIT发觉了这个文件,但这个文件是否要纳入GIT的版本控制还是要由我们自己决定,比如编译生成的中间文件,我们肯定不想纳入版本控制。下面就来看下文件状态。

三、GIT文件操作

版本控制就是对文件的版本控制,对于Linux来说,设备,目录等全是文件,要对文件进行修改、提交等操作,首先要知道文件当前在什么状态,不然可能会提交了现在还不想提交的文件,或者要提交的文件没提交上。

文件状态

GIT仓库所在的目录称为工作目录,这个很好理解,我们的工程就在这里,工作时也是在这里做修改。

在工作目录中的文件被分为两种状态,一种是已跟踪状态(tracked),另一种是未跟踪状态(untracked)。只有处于已跟踪状态的文件才被纳入GIT的版本控制。如下图:

当我们往工作目录添加一个文件的时候,这个文件默认是未跟踪状态的,我们肯定不希望编译生成的一大堆临时文件默认被跟踪还要我们每次手动将这些文件清除出去。用以下命令可以跟踪文件:

git add <file>

上图中右边3个状态都是已跟踪状态,其中的灰色箭头只表示untracked<-->tracked的转换而不是untracked<-->unmodified的转换,新添加的文件肯定算是被修改过的。那么,staged状态又是什么呢?这就要搞清楚GIT的三个工作区域:本地数据(仓库)目录,工作目录,暂存区,如下图所示:

git directory就是我们的本地仓库.git目录,里面保存了所有的版本信息等内容。

working driectory,工作目录,就是我们的工作目录,其中包括未跟踪文件及已跟踪文件,而已跟踪文件都是从git directory取出来的文件的某一个版本或新跟踪的文件。

staging area,暂存区,不对应一个具体目录,其时只是git directory中的一个特殊文件。

当我们修改了一些文件后,要将其放入暂存区然后才能提交,每次提交时其实都是提交暂存区的文件到git仓库,然后清除暂存区。而checkout某一版本时,这一版本的文件就从git仓库取出来放到了我们的工作目录。

文件状态的查看

那么,我们怎么知道当前工作目录的状态呢?哪些文件已被暂存?有哪些未跟踪的文件?哪些文件被修改了?所有这些只需要一个命令,git status,如下图所示:

GIT在这一点做得很好,在输出每个文件状态的同时还说明了怎么操作,像上图就有怎么暂存、怎么跟踪文件、怎么取消暂存的说明。

文件暂存

在上图中我们可以很清楚地看到,filea未跟踪,fileb已被暂存(changes to be committed),但是怎么还有一个fileb是modified但unstaged呢?这是因为当我们暂存一从此文件时,暂存的是那一文件当时的版本,当暂存后再次修改了这个文件后就会提示这个文件暂存后的修改是未被暂存的。

接下来我们就看怎么暂存文件,其实也很简单,从上图中可以看到GIT已经提示我们了:use "git add <file>..." to update what will be committed,通过

git add <file>...

就可以暂存文件,跟踪文件同样是这一个命令。在这个命令中可以使用glob模式匹配,比如"file[ab]",也可以使用"git add ."添加当前目录下的所有文件。

取消暂存文件是

git reset HEAD <file>...

若修改了一个文件想还原修改可用

git checkout -- <file>...

查看文件修改后的差异

当我们修改过一些文件之后,我们可能想查看我们都修改了什么东西,用"git status"只能查看对哪些文件做了改动,如果要看改动了什么,可以用:

git diff

比如下图:

--a表示修改之前的文件,+++b表示修改后的文件,上图表示在fileb的第一行后添加了一行"bb",原来文件的第一行扩展为了修改后的1、2行。

但是,前面我们明明用"git status"看到filesb做了一些修改后暂存了,然后又修改了fileb,理应有两次修改的,怎么只有一个?

因为"git diff"显示的是文件修改后还没有暂存起来的内容,那如果要比较暂存区的文件与之前已经提交过的文件呢,毕竟实际提交的是暂存区的内容,可以用以下命令:

/dev/null表示之前没有提交过这一个文件,这是将是第一次提交,用:

git diff --staged

是等效的,但GIT的版本要大于1.6.1。

再次执行"git add"将覆盖暂存区的内容。

四、GIT分支

分支被称之为GIT最强大的特性,因为它非常地轻量级,如果用Perforce等工具应该知道,创建分支就是克隆原目录的一个完整副本,对于大型工程来说,太费时费力了,而对于GIT来说,可以在瞬间生成一个新的分支,无论工程的规模有多大,因为GIT的分支其实就是一指针而已。在了解GIT分支之前,应该先了解GIT是如何存储数据的。

前面说过,GIT存储的不是文件各个版本的差异,而是文件的每一个版本存储一个快照对象,然后通过SHA-1索引,不只是文件,包换每个提交都是一个对象并通过SHA-1索引。无论是文本文件,二进制文件还是提交,都是GIT对象。

新建分支

git branch <branch-name>

有时需要在新建分支后直接切换到新建的分支,可以直接用checkout的-b选项

删除分支

git branch -d <branch-name>

如果在指定的分支有一些unmerged的提交,删除分支会失败,这里可以使用-D参数强制删除分支。

git branch -D <branch-name>

检出分支或提交

检出某一分支或某一提交是同一个命令

git checkout <branch-name> | <commit>

标签-tag

作为一个版本控制工具,针对某一时间点的某一版本打tag的功能是必不可少的,要查看tag也非常简单,查看tag使用如下命令:

git tag

Git 使用的标签有两种类型:轻量级的(lightweight)和含附注的(annotated)。轻量级标签就像是个不会变化的分支,实际上它就是个指向特定提交对象的引用。而含附注标签,实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明,标签本身也允许使用 GNU Privacy Guard (GPG) 来签署或验证。

轻量级标签只需在git tag后加上tag的名字,如果tag名字

git tag <tag_name>

REPO

开启一个新的主题,其实就是每个Project都新建一个分支。

repo start <topic_name>

在当前目录下初始化repo,会在当前目录生生成一个.repo目录,像Git Project下的.git一样,-u指定url,可以加参数-m指定manifest文件,默认是default.xml,.repo/manifests保存manifest文件。.repo/projects下有所有的project的数据信息,repo是一系列git project的集合,每个git project下的.git目录中的refs等目录都是链接到.repo/manifests下的。

repo init -u <url> [OPTIONS]

可以根据当前各Project的版本信息生成一个manifest文件

repo manifest

同步Code

repo sync [PROJECT1...PROJECTN]

查看本地所有Project的修改,在每个修改的文件前有两个字符,第一个字符表示暂存区的状态

repo status

查看所有分支

repo branch或repo branches

查看修改

repo diff

对指定的Project列表或所有Project执行命令COMMAND,加上-p参数可打印出Project的路径。

撤销整个工程的本地修改:

repo forall -c 'git reset --hard HEAD;git clean -df;git rebase --abort'