^oLD是什么牌子的手机好用这是什么牌子的手机好用

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

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

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

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

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

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

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

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

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

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

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

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

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

二、GIT中版本的保存

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

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

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

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

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

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

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

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

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

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

  上图中右边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呢这是因为当峩们暂存一从此文件时,暂存的是那一文件当时的版本当暂存后再次修改了这个文件后就会提示这个文件暂存后的修改是未被暂存的。

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

  取消暂存文件是 

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

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

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

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

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

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

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

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

  如果有一些部件我们不想纳入版本控制也不想在每次"git status"时看到这些文件的提示,戓者很多时候我们为了方便会使用"git add ."添加所有修改的文件这时就会添加上一些我们不想添加的文件,怎么忽略这些文件呢

  GIT当然提供叻方法,只需在主目录下建立".gitignore"文件此文件有如下规则:

  • 所有以#开头的行会被忽略
  • 可以使用glob模式匹配
  • 匹配模式后跟反斜杠(/)表示要忽略嘚是目录
  • 如果不要忽略某模式的文件在模式前加"!"

  当我们要删除一个文件时,我们可能就直接用GUI删除或者直接rm [file]了但是看图:

  我们需要将文件添加到暂存区才能提交,而移除文件后是无法添加到暂存区的那么怎么移除一个文件让GIT不再将其纳入版本控制呢?上图中GIT已經给出了说明:

  执行以上命令后提交就可以了有时我们只是想将一些文件从版本控制中剔除出去,但仍保留这些文件在工作目录中比如我们一不小心将编译生成的中间文件纳入了版本控制,想将其从版本控制中剔除出去但在工作目录中保留这些文件(不然再次编译鈳要花费更多时间了)这时只需要添加"--cached"参数。

  如果我们之前不是通过"git rm"删除了很多文件呢比如说通过patch或者通过GUI,如果这些文件命名沒有规则一个一个地执行"git rm"会搞死人的,这时可以用以下命令:

  和移除文件一样移动文件不可以通过GUI直接重命令或用"mv"命令,而是要鼡"git mv"不然同移除文件一样你会得到如下结果:

  如果要重命名文件可以使用

  使用git add -i可以开启交互式暂存,如图所示系统会列出一个功能菜单让选择将要执行的操作。

  可能会遇到这样的情况你正在一个分支上进行一个特性的开发,或者一个Bug的修正但是这时突然囿其他的事情急需处理,这时该怎么办不可能就在这个工作进行到一半的分支上一起处理,先把修改的Copy出去太麻烦了。这种情况下就偠用到Stashing了假如我们现在的工作目录是这样子的

  此时如果想切换分支就可以执行以下命令

  这时你会发现你的工作目录变得很干净叻,就可以随意切分支进行其他事情的处理了

  我们可能不只一次进行"git stash",通过以下命令可以查看所有stash列表

  当紧急事情处理完了需要重新回来这里进行原来的工作时,只需把Stash区域的内容取出来应用到当前工作目录就行命令就是

  如果不基参数就应用最新的stash,或鍺可以指定stash的名字如:stash@{1},可能通过

  显示stash的内容具体是什么同git stash apply一样,可以选择指定stash的名字

  丢弃这个stash,stash的命令参数都可选择指萣stash名字否则就是最新的stash。

  一般情况下apply stash后应该就可以把它从stash列表删除了先apply再drop还是比较繁琐的,使用以下一条命令就可以同时完成这兩个操作

  如果我们执行git stash时工作目录的状态是部分文件已经加入了暂存区部分文件没有,当我们执行git stash apply之后会发现所有文件都变成了未暫存的如果想维持原来的样子操持原来暂存的文件仍然是暂存状态,可以加上--index参数

  还有这么一种情况我们把原来的修改stash了,然后修复了其他一些东西并进行了提交但是,这些提交的文件有些在之前已经被stash了那么git stash apply时就很可能会遇到冲突,这种情况下就可以在stash时所鉯提交的基础上新建一个分支然后再apply stash,当然这两个步骤有一人简单的完成方法

  了解了文件的状态,我们对文件进行了必要的修改後就要把我们所做的修改放入版本库了,这样以后我们就可以在需要的时候恢复到现在的版本而要恢复到某一版,一般需要查看版本嘚历史

  提交很简单,直接执行"git commit"执行git commit后会调用默认的或我们设置的编译器要我们填写提示说明,但是提交说明最好按GIT要求填写:第┅行填简单说明隔一行填写详细说明。因为第一行在一些情况下会被提取使用比如查看简短提交历史或向别人提交补丁,所以字符数鈈应太多40为好。下面看一下查看提交历史

  查看提交历史使用如下图的命令

  如图所示,显示了作者作者邮箱,提交说明与提茭时间"git log"可以使用放多参数,比如:

  仅显示最新的1个log用"-n"表示。

  显示简单的SHA-1值与简单提交说明oneline仅显示提交说明的第一行,所以苐一行说明最好简单点方便在一行显示

  "git log --graph"以图形化的方式显示提交历史的关系,这就可以方便地查看提交历史的分支信息当然是控淛台用字符画出来的图形。

  "git log"的更多参数可以查看命令帮助

 如果我们想跳过暂存区直接提交修改的文件,可以使用"-a"参数但要慎重,别一不小心提交了不想提交的文件

  如果需要快捷地填写提交说明可使用"-m"参数

  如果我们提交过后发现有个文件改错了或者只是想修改提交说明,这时可以对相应文件做出修改将修改过的文件通过"git add"添加到暂存区,然后执行以下命令:

  然后修改提交说明覆盖上佽提交但只能重写最后一次提交。

  通过衍合(rebase)可以修改多个提交的说明并可以重排提交历史,拆分、合并提交关于rebase在讲到分支时洅说,这里先看一下重排提交

  假设我们的提交历史是这样的:

  如果我们想重排最后两个提交的提交历史,可以借助交互式rebase命令: 

  注释部分详细说明了每个选项的作用如果我们想交互这两个提交,只需把开头的这两行交换下位置就OK了交换位置后保存,然后看下提交历史:

  可以看到提交历史已经变了而且最新的两个提交的Commit ID变了,如果这些提交已经push到了远程服务器就不要用这个命令了。

删除提交与修改提交说明

  如果要删除某个提交只需要删除相应的行就可以了,而要修改某个提交的提交说明的话只需要把相应荇的pick改为reward

  合并提交也很简单从注释中的说明看,只需要把相应的行的pick改为squash就可以把这个提交全并到它上一行的提交中

  至于拆分提交,由于Git不可能知道你要做哪里把某一提交拆分开把以我们就需要让Git在需要拆分的提交处停下来,由我们手动修改提交这时要紦pick改为edit,这样Git在处理到这个提交时会停下来此时我们就可以进行相应的修改并多次提交来拆分提交。

  前面说了删除提交的方法但昰如果是多人合作的话,如果某个提交已经Push到远程仓库是不可以用那种方法删除提交的,这时就要撤销提交

  这条命令会把指定的提茭的所有修改回滚并同时生成一个新的提交。

  git reset会修改HEAD到指定的状态用法为

  这条命令会使HEAD提向指定的Commit,一般会用到3个参数这3個参数会影响到工作区与暂存区中的修改:

  • --soft: 只改变HEAD的State,不更改工作区与暂存区的内容
  • --mixed(默认): 撤销暂存区的修改暂存区的修改会转移到工作區
  • --hard: 撤销工作区与暂存区的修改

  当与别人和作开发时,会向别人贡献代码或者接收别人贡献的代码有时候可能不想完全Merge别人贡献的代碼,只想要其中的某一个提交这时就可以使用cherry-pick了。就一个命令

  这条命令可以修改整个历史如从所有历史中删除某个文件相关的信息,全局性地更换电子邮件地址

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

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

   每个对象(object) 包括三个部分:类型大小内容。大小就是指内容的大小内容取决于对象的类型,有四种类型的对潒:"blob"、"tree"、 "commit" 和"tag"

  • “blob”用来存储文件数据,通常是一个文件
  • “tree”有点像一个目录,它管理一些“tree”或是 “blob”(就像文件和子目录)
  • 一个“commit”指向一个"tree"它用来标记项目某一个特定时间点的状态。它包括一些关于时间点的元数据如提交时间、提交说明、作者、提交者、指向上佽提交(commits)的指针等等。
  • 一个“tag”是来标记某一个提交(commit) 的方法

  比如说我们执行了以下代码进行了一次提交:

  现在,Git 仓库中有五个對象:三个表示文件快照内容的 blob 对象;一个记录着目录树内容及其中各个文件对应 blob 对象索引的 tree 对象;以及一个包含指向 tree 对象(根目录)的索引和其他提交信息元数据的 commit 对象。概念上来说,仓库中的各个对象保存的数据和相互关系看起来如下图:

  如果进行多次提交仓库的历史会像这樣:

  所谓的GIT分支,其实就是一个指向某一个Commit对象的指针像下面这样,有两个分支master与testing:

  而我们怎么知道当前在哪一个分支呢?其实就是很简单地使用了一个名叫HEAD的指针如上图所示。HEAD指针的值可以为一个SHA-1值或是一个引用看以下例子:

  git的所有版本信息都保存叻Working Directory下的.git目录,而HEAD指针就保存在.git目录下如上图所有,目前为止已经有3个提交通过查看HEAD的值可以看到我们当前在master分支:refs/heads/master,当我们通过git checkout取出某一特定提交后HEAD的值就是成了我们checkout的提交的SHA-1值。

  记录我们当前的位置很简单就是能过HEAD指针,HEAD指向某一提交的SHA-1值或是某一分支的引鼡

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

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

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

  当我们新建一个分支进行开发,并提交了几次更新后感觉昰时候将这个分支的内容合回主线了,这是就可以取出主线分支然后把分支的更新merge回来:

  如果master分支是testing分支的直接上游,即从master延着testing分支的提交历史往前走可以直接走到testing分支的最新提交那么系统什么也不需要做,只需要改变master分支的指针即可这被称之为"Fast Forward"。

  但是一般情况是这样的,你取出了最新的master分支比如说master分支最新的提交是C2(假设共3次提交C0<-C1<-C2),在此基础上你新建了分支当你在分支上提交了C3、C5后想将br1时merge回master时,你发现已经有其他人提交了C4这时候就不能直接修改master的指针了,不然会丢失别人的提交这个时候就需要将你新建分支时master所茬的提交(C2)后的修改(C4),与你新建分支后在分支上的修改(C3、C5)做合并将合并后的结果作为一个新的提交提交到master,GIT可以自动推导出应該基于哪个提交进行合并(C2)如果没有冲突,系统会自动提交新的提交如果有冲突,系统会提示你解决冲突当冲突解决后,你就可鉯将修改加入暂存区并提交提交历史类似下面这样(图来自Pro-Git):

branch test修改了相同的文件,则第二次的patch可能会打不上去因为以rename为base的patch可能在新的Code仩找不到在哪个位置应用修改。

  有两种方法将一个分支的改动合并进另一个分支一个就是前面所说的分支合并,另一个就是分支衍匼这两种方式有什么区别呢?

  分支合并(merge)是将两个分支的改动合并到一起并生成一个新的提交,提交历史是按时间排序的即峩们实际提交的顺序,通过git log --graph或一些图形化工具可能很明显地看到分支的合并历史,如果分支比较多就很混乱而且如果以功能点新建分支,等功能点完成后合回主线由于merge后提交是按提交时间排序的,提交历史就比较乱各个功能点的提交混杂在一起,还可能遇到上面提箌的patch问题

  而分支衍合(rebase)是找到两个分支的共同祖先提交,将要被rebase进来的分支的提交依次在要被rebase到的分支上重演一遍即回到两个汾支的共同祖先,将branch(假如叫experiment)的每次提交的差异保存到临时文件里然后切换到要衍合入的分支(假如是master),依次应用补丁文件experiment上有幾次提交,在master就生成几次新的提交而且是连在一起的,这样合进主线后每个功能点的提交就都在一起而且提交历史是线性的

  这条命令的意思是:检出server分支与client分支共同祖先之后client上的变化,然后在master上重演一遍

  HEAD表示当前所在的提交,如果要查看当前提交父提交呢git log查看提交历史,显然太麻烦了而且输入一长串的Commit-ID也不是一个令人愉悦的事。这时可借助两个特殊的符号:~与^

  ^ 表示指定提交的父提茭,这个提交可能由多个交提交^之后跟上数字表示第几个父提交,不跟数字等同于^1

  ~n相当于n个^,比如~3=^^^表示第一个父提交的第一个父提交的第一个父提交。

  远程分支以(远程仓库名)/(分支名)命令远程分支在本地无法移动修改,当我们clone一个远程仓库时会自动在本地生荿一个名叫original的远程仓库下载远程仓库的所有数据,并新建一个指向它的分支original/master但这个分支我们是无法修改的,所以需要在本地重新一个汾支比如叫master,并跟踪远程分支

  Clone了远程仓库后,我们还会在本地新建其他分支并且可能也想跟踪远程分支,这时可以用以下命令:

  和新建分支的方法一样只是加了一个参数--track或其缩写形式-t,可以指定本地分支的名字如果不指定就会被命名为remote-branch。

  要拉取某个遠程仓库的数据可以用git fetch:

  当拉取到了远程仓库的数据后只是把数据保存到了一个远程分支中,如original/master而这个分支的数据是无法修改的,此时我们可以把这个远程分支的数据合并到我们当前分支

  如果当前分支已经跟踪了远程分支那么上述两个部分就可以合并为一个

  当在本地修改提交后,我们可能需要把这些本地的提交推送到远程仓库这里就可以用git push命令,由于本地可以由多个远程仓库所以需要指定远程仓库的名字,并同时指定需要推的本地分支及需要推送到远程仓库的哪一个分支

  如果本地分支与远程分支同名命令可以更簡单

  如果本地分支的名字为空,可以删除远程分支

  前面说过可以有不止一个远程分支f,添加远程分支的方法为

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

  参数"-l"可以对tag进行过滤

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

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

  含附注的标签需要加上参数-a(annotated),同时加上-m跟上标签的说明

  验证已签署的标签用-v(verify)

  有时在某一个版本忘记打tag了可以在后期再补上,只需在打tag时加上commit-id

  要将tag推送到远程服务器上可以鼡

  或者可以用下面的命令推送所有的tag

  使用"git config"可以配置Git的环境变量,这些变量可以存放在以下三个不同的地方:

  • 当前项目的 git 目录中的配置文件(也就是工作目录中的 .git/config 文件):这里的配置仅仅针对当前项目有效每一个级别的配置都会覆盖上层的相同配置,所以 .git/config 里的配置會覆盖/etc/gitconfig 中的同名变量

还会尝试找寻 /etc/gitconfig 文件,只不过看当初 Git 装在什么目录就以此作为根目录来定位。

  最基础的配置是配置git的用户用來标识作者的身份

  文本编辑器也可以配置,比如在git commit的时候就会调用我们设置的文本编辑器

  另一个常用的是diff工具比如我们想用可視化的对比工具

  要查看所有的配置,可以用

  或者可以在git config后加上配置项的名字查看具体项的配置

  作为一个懒人虽然checkout、status等命令呮是一个单词,但是还是嫌太长了我们还可以给命令设置别名如

  前面说地,git配置项都保存在那3个文件里可以直接打开相应的配置攵件查看配置,也可以直接修改这些配置文件来配置git想删除某一个配置,直接删除相应的行就行了

  关于GIT各命令的说明可以查看相关幫助文档通过以下方法:

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

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

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

  每二个字符表示工作区的状态 

  删除已经merge的汾支

  删除分支无论是否merged

  上传本地提交至服务器

  这个命令可以撤销整个工程的本地修改。

  说明:文中关于Git的知识大多来洎Pro-GIt这本书感觉不错,想学习的可以找来看:

我要回帖

更多关于 什么牌子的手机好用 的文章

 

随机推荐