Git 从安装到使用学习记录

一、关于版本控制

    什么是版本控制? 版本控制是一种记录一个或若干个文件内容变化,以便将来查阅特定版本修订情况的系统

    如果你是位图形或网页设计师,可能会需要保存某一幅图片或页面布局文件的所有修订版本(这或许是你非常渴望拥有的功能),采用版本控制系统(VCS)是个明智的选择。 有了它你就可以将某个文件回溯到之前的状态,甚至将整个项目都回退到过去某个时间点的状态,你可以比较文件的变化细节,查出最后是谁修改了哪个地方,从而找出导致怪异问题出现的原因,又是谁在何时报告了某个功能缺陷等等。 使用版本控制系统通常还意味着,就算你乱来一气把整个项目中的文件改的改删的删,你也照样可以轻松恢复到原先的样子。 但额外增加的工作量却微乎其微。

 

二、版本控制系统分类

2.1、本地版本控制系统

    一种方式是直接复制整个项目来保存不同的版本,唯一的好处是简单,但是特别容易犯错;

    为了解决这个问题,人们很久以前就开发了许多种本地版本控制系统,大多都是采用某种简单的数据库来记录文件的历次更新差异。

    比较流行的一种叫做RCS,它的工作原理是在硬盘上保存补丁集(补丁是指文件修订前后的变化);通过应用所有的补丁,可以重新计算出各个版本的文件内容。

 

2.2、集中化的版本控制系统

    本地版本控制能解决保存各个版本的问题,但是无法满足在不同系统上的开发者协同工作问题,于是,集中化的版本控制系统应运而生(Centralized Version Control Systems,简称 CVCS);

    这类系统,诸如 CVS、Subversion 以及 Perforce 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。 多年以来,这已成为版本控制系统的标准做法。

Git 从安装到使用学习记录

    这种做法带来了许多好处,特别是相较于老式的本地 VCS 来说。 现在,每个人都可以在一定程度上看到项目中的其他人正在做些什么。 而管理员也可以轻松掌控每个开发者的权限,并且管理一个 CVCS 要远比在各个客户端上维护本地数据库来得轻松容易。 

    事分两面,有好有坏。 这么做最显而易见的缺点是*服务器的单点故障。 如果宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。 如果中心数据库所在的磁盘发生损坏,又没有做恰当备份,毫无疑问你将丢失所有数据——包括项目的整个变更历史,只剩下人们在各自机器上保留的单独快照。 本地版本控制系统也存在类似问题,只要整个项目的历史记录被保存在单一位置,就有丢失所有历史更新记录的风险。

 

2.3、分布式版本控制系统

   为解决集中化的版本控制的*服务器存在的的单点故障的缺陷,分布式版本控制系统(Distributed Version Control System,简称 DVCS)面世了;

    像 Git、Mercurial、Bazaar 以及 Darcs 等,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来,这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。 因为每一次的克隆操作,实际上都是一次对代码仓库的完整备份。

Git 从安装到使用学习记录

 

 三、Git学习记录

3.1、理论:Git基础:

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

    什么意思呢?类似svn版本控制系统,它保存的是一组基本文件和后续每个文件相对于初始版本的的增量,即每个文件与初始版本的差异;而Git是对整个项目当时的所有文件制作一个快照并保存这个快照的索引,当然,如果文件没有修改,Git不再重新存储该文件,只是保留一个链接指向之前存储的文件

  • Git近乎所有的操作都是本地执行

    因为将项目clone至本地后,本地磁盘中保留了项目的完整历史,所以如果需要获取某个历史,Git不需要外连到服务器就可以做到,直接从本地读取即可;如果在没有网络的情况下,做了某些工作也可以愉快的提交,等有网络的时候再push至其他库

  • Git一般只添加数据

    执行的 Git 操作,几乎只往 Git 数据库中增加数据。 很难让 Git 执行任何不可逆操作,或者让它以任何方式清除数据。 同别的 VCS 一样,未提交更新时有可能丢失或弄乱修改的内容;但是一旦你提交快照到 Git 中,就难以再丢失数据,特别是如果你定期的推送数据库到其它仓库的话

 

3.2、理论:Git的三种状态

    Git有三种状态,你的文件可能处于其中之一:

  • 已提交(committed):数据已经安全的保存到本地数据库
  • 已修改(modified):修改了文件,但是还没有保存到本地数据库
  • 已暂存(staged):对一个已修改的文件做了标记,包含在下一次提交的快照中

由此引出了Git项目的三个工作区域概念:

  • Git仓库:Git 用来保存项目的元数据和对象数据库的地方,从其它计算机克隆仓库时,拷贝的就是这里的数据。
  • 工作目录:对项目的某个版本独立提取出来的内容,放置在磁盘上供修改
  • 暂存区域:是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中。 有时候也被称作“索引”

Git 从安装到使用学习记录

基本的 Git 工作流程如下:

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

  2. 暂存文件,将文件的快照放入暂存区域。

  3. 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录。

 

3.3、获取一个Git仓库

  1. 在现有目录 或 创建一个目录初始化仓库
  2. 从服务器克隆一个现有的Git仓库

对1:进入目录,敲 git init 命令:

如下图,命令会在目录创建一个 .git 的子目录,这个目录中含有你初始化的 Git 仓库中所有的必须文件,这些文件是 Git 仓库的骨干

Git 从安装到使用学习记录

 

对2:

    Git 支持多种数据传输协议,  https:// 协议, git:// 协议或者使用 SSH 传输协议,比如 [email protected]:path/to/repo.git

git clone [url]  //默认本地仓库名字
git clone [url] [文件夹名字]   //指定本地仓库的目录名字

3.4、添加文件到版本库

    分两步:

git add 文件名   // 可提交多个,之间用空格隔开
git commit -m <message>   // -m 后面接的是本次提交的注释说明

Git Bash 命令行中,对于你做的操作,会有一些说明提示你干了什么事情

Git 从安装到使用学习记录

为什么Git添加文件需要 addcommit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:

$ git add file1.txt
$ git add file2.txt file3.txt
$ git commit -m "add 3 files."

3.5、 git status 命令的使用

    我分别修该两个本地仓库中的文件,然后运行 git status 命令查看结果:

    命令结果告诉我们两个文件被修改了,,要么用 git add <file> 操作更新这些文件,要么用 git checkout -- <file> 丢弃工作区域中所做的修改, 可见这些提示信息差不多已经提示了我么下一步可以做一些什么操作,很666

Git 从安装到使用学习记录

    如果此时我想知道具体修改了什么信息该怎么办呢,此时有一个经常搭配使用的命令 git diff <file>, 就可以很清晰的看到,(git diff <file>是工作区和暂存区的文件做比较(即和上一次git add 的内容的区别)):

Git 从安装到使用学习记录

重新提交后,git status 可以看到显示工作区是干净的:

Git 从安装到使用学习记录

3.6、版本回退

    在Git中,当你觉得文件修改到一定程度的时候,就可以“保存一个快照”,这个快照在Git中被称为commit。一旦你把文件改乱了,或者误删了文件,还可以从最近的一个commit恢复,然后继续工作,而不是把几个月的工作成果全部丢失

    如果我需要回到某一个版本“快照”,首先我需要找到这个“快照”(每一次commit都有一个唯一的标识),用 git log 查看:

Git 从安装到使用学习记录

如果觉得信息太多太乱可以用 git log --pretty=oneline ,将一次提交的历史记录在一行显示:

Git 从安装到使用学习记录

    日志信息中,前面那一长串东西,是标识一次提交的唯一标识,叫 commit id (版本号),

    这是Git 用以计算校验和的机制,叫做 SHA-1 散列(hash,哈希)。 这是一个由 40 个十六进制字符(0-9 和 a-f)组成字符串,基于

Git 中文件的内容或目录结构计算出来。

    既然 commit id 标识了唯一特定的版本,我们就可以用这个值来做版本回退

    首先,Git必须知道当前是哪个版本,在Git中使用 HEAD 表示当前版本,上个版本就是HEAD^,上上个就是HEAD^^, 如果是一百个呢?理论是是可以写一百个^ 符号的,,但是容易出错而且很蠢啊,所以有另外一种表示:HEAD~100

Git 从安装到使用学习记录

此时,如果我后悔了,我想要恢复到我的最新版本,但是此时我用 git log 查看记录到的最新的历史记录是我回退以后的,找不到最新的版本的提交了怎么办? 此时Git 提供了一个命令 git reflog 用来记录每一次的提交:

Git 从安装到使用学习记录

3.7、git中 工作区、暂存区的 理解

    本地仓库目录就是工作区,工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库;

    Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫 HEAD

Git 从安装到使用学习记录

 

3.8、撤销修改

    这里的撤销修改是指针对还没有推送(push)到远程仓库的情况

场景一:修改了工作区文件内容,但是还没有git add 到暂存区,使用git status 命令:

Git 从安装到使用学习记录

    提示可以看到,使用 git checkout -- <file>可以放弃工作区的修改修改:

Git 从安装到使用学习记录

 

场景二:修改了工作区的文件内容,使用git add  提交到了暂存区:

Git 从安装到使用学习记录

 

场景三:修改了工作区文件内容后,先后做了git add 和 git commit操作,已经提交到本地仓库中去

    做版本回退,git commit 后,会有一个commit id ,使用 git reset --hard <commit id>,就回到了你指定的版本

 

3.9、删除文件

    在Git中,增加、删除都是一种修改操作,当在工作区中删除了某一文件后,工作区和版本库就不一致;

    使用git status 我们可以看到,可以有两种选择:

1、确实要删除, git rm <file> 后, 然后 git commit 即可删除

2、误删了,可以使用git checkout -- <file>恢复到最新版本

Git 从安装到使用学习记录

     命令git rm 用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容(即你还未提交的部分)。

 

3.10、添加一个远程库

    上面 3.x 章节的所有操作都是在本地仓库做的,现在我们想把本地的仓库放到远程仓库上去,,相当于做了一个备份,同时其他人也可以通过这个远程仓库来协作我们的开发。

    首先,在GitHub上新建一个仓库,登录 github ,点击右上角的 + 号:

Git 从安装到使用学习记录

因为Git使用SSH连接,我们往GitHub推送内容的时候,会有ssh鉴权,此时我们需要生产一个SSH**:

Git 从安装到使用学习记录

把上面公钥中的内容复制,配置到GitHub上去:

Git 从安装到使用学习记录

然后,我们建立本地仓库和远程仓库之间的关联,把代码提交到远程仓库上去(过程中遇到的坑直接写在了图片中),(如果要删除已有的github远程库:git remote rm <远程库的名字(比如origin)>):

Git 从安装到使用学习记录

     要关联一个远程库,使用命令git remote add origin [email protected]:path/repo-name.git

    关联后,使用命令git push -u origin master第一次推送master分支的所有内容;

    此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;

 

3.11、分支

  3.11.1、git中的分支:每一次提交,Git都把提交的历史串成一条时间线,这条时间线就是一个分支; 其中master叫做主分支,在初始化为Git仓库后就会自动创建,HEAD 指向当前分支,而当前分支指向最新的提交,看下面的示意图:

Git 从安装到使用学习记录

    上面示意图中是在单分支,也就是但时间轴的情况下,假如我在某一个提交节点,新建了一条分支,过程是怎样的呢?看下面示意图:

Git 从安装到使用学习记录

下面敲一下这个过程中的一些命令:

Git 从安装到使用学习记录

在develop分支上做完了修改后,切换回master分支,并把修改合并到master分支上来:

Git 从安装到使用学习记录

3.11.2、可是事实上,我们不会一直这么顺利,Git有一个合并冲突的概念; 假如,如果是这样一种情况,我在develop分支上,在first.txt这个文件中加了一行:

第一次使用git版本控制系统
加一行
在develop分支上加的一行
git is a eash or harf?    //在develop分支上新加的行

然后在master分支上也修改了这个文件,新加了一行:

第一次使用git版本控制系统
加一行
在develop分支上加的一行
git is easy      // 在master分支上新增的一行

然后在master分支上合并develop分支中修改的内容;  可以看到,合并发生了冲突,合并失败,此时就需要我们手动解决冲突,然后在提交文件, 并且此时分支的状态是merging。

Git 从安装到使用学习记录

冲突的后的文件时什么样的呢?看下面:

第一次使用git版本控制系统
加一行
在develop分支上加的一行
<<<<<<< HEAD
git is easy
=======
git is a eash or harf? 
>>>>>>> develop

    解决冲突后,提交代码,(记得一定要解决冲突以后再提交代码,push到远程仓库; 虽然冲突并不影响你提交代码,但是肯定会影响你的工程运行,因为这个是一个错误的代码形式,很可能出现很严重的后果),此时可以用git log 查看一下分支的合并情况:

Git 从安装到使用学习记录

3.11.3、 需要了解一点,合并分支时,Git默认会使用Fast forward 模式(比如在master上:git merge dev:就是将master的指针指向dev分支的最新提交,再把HEAD指向master),但是这种模式下,如果删除分支,会丢掉分支信息(commit id 这些),这个可以从日志看出来:

Fast forward:

Git 从安装到使用学习记录

如果强制禁用Fast forward(使用 --no-ff),Git会在merge的时候生成一个新的commit:

Git 从安装到使用学习记录

3.11.4、 有一种情况: 我在一个分支比如develop上正在愉快的写着我的代码, 突然,项目经理说: XXX,这个有一个bug需要你马上修复一下,此时我们不得不暂时停下手中的工作去改bug,但是等等,我写到一半的代码怎么办,也没法提交啊; 此时,Git提供了一个stash功能,把当前的工作现场储存起来,修改完bug后我们再取回刚刚的工作现场,完美 ^_^:

Git 从安装到使用学习记录

3.11.5、 没有被合并过的分支不能普通删除,如果确切要删除,可以使用强制删除

Git 从安装到使用学习记录

3.11.6、 git在分支下的多人协作开发

    远程库存在的意义有很多,最主要的两点就是:1、在多人协作开发项目中,使项目的所有内容对团队成员可见,2、在远程服务器备份项目,防止丢失;对于第一点,涉及到一个往远程库推送和从远程库拉取项目信息的这么两个过程

    从远程库 做 git clone 操作时,实际上Git 自动把本地 分支 和远程分支对应起来的,并且,远程仓库的默认名称是 origin ,后续对代码做了修改,想要推送到远程服务器上去:

Git 从安装到使用学习记录

假如现在项目组新入职了一位小伙伴,它从远程库中拉取了代码分支master,但是平时开发都是在develop分支上的, 此时他需要先创建远程origin的develop分支到本地:

Git 从安装到使用学习记录

其实也可以直接指定远程库上的某个分支来 git clone:

Git 从安装到使用学习记录

这个小伙伴在分支上推送了他写的代码后,此时,碰巧你也对同样的文件做了修改,并试图推送到远程库:

Git 从安装到使用学习记录

发现推送失败,因为你的小伙伴已经提交过代码到远程库了,现在你的本地仓库不是指向最新的提交,可以看见Git已经提示我们了,先做git pull 操作,把最新提交从远程库中先取出来:

Git 从安装到使用学习记录

上图中,先做git pull 操作,提示我们没有建立本地develop分支到远程origin/develop分支的连接,提示我们用 git branch --set-upstream-to=origin/<branch> develop 命令建立联系(这个操作只需做一次), 后续再git pull 的时候就成功了,,只是存在冲突,解决冲突参考:3.11.2

总结一下多人协作的工作模式:

1、首先,可以试图用git push origin <branch-name>推送自己的修改;
2、如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
3、如果合并有冲突,则解决冲突,并在本地提交;
4、没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!
5、如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>。
6、有冲突就解决冲突在git push ...,没有冲突就直接git push ...

3.11.7、 Git中的标签

    为什么git 要有标签(tag)这个概念? 为了便于查看啊,在某个时间点,比如我2018-10-28 有一个新版本要发布,在这个时间点上肯定有一个 commit id  最新的提交 表示这个版本, 但是,你是愿意看一个 v1.0 表示这个版本,还是愿意看一串 4hy79igf.... 这样一个40个十六进制长度的字符串呢?另外一个原因,标签也便于管理

Git 从安装到使用学习记录

Git 从安装到使用学习记录

3.11.8、Git忽略特殊文件

    什么意思呢?有时候,在git工作空间中的某些文件,我们并不想把它提交,但是 git status 时,又总是显示这些文件,如果有强迫症的同学估计想砸电脑,

    此时 Git 提供给我们一个功能,就是 在Git工作区的根目录下创建一个特殊的 .gitignore 文件(注意:文件名字必须为.gitignore,最好用notepad++ 编辑器写好,然后另存为,这里我遇到了坑,导致文件一直不生效) , 在这个文件中配置那些你不想提交的文件, 这样,git 就会忽略掉这些文件。 这个文件怎么写?可以从这个获取:https://github.com/github/gitignore, Git已经很贴心为我们准备了各种配置文件。

    配置完成后,把这个文件提交到Git,就生效了:

我在Git工作区创建了 .gitignore 文件, 并在其中配置了 *.class (意识是忽略所有class文件), 将它push到远程库以后, 再在工作区新建了一个 a.class 文件

Git 从安装到使用学习记录

然后在git中去查看,可以看到, 这个就解决了你想要把文件放到工作区,但是又不想提交的问题,强迫症同学也可以深呼一口气,这下舒服了:

Git 从安装到使用学习记录

3.11.9、配置别名

    别名的意义在于简化命令的敲打,对于一些很长很难记的单词或语句,你可以配置成几个简单的字母,后续你就可以用这个字母来代替那个单词或者语句,Git会去你配置的别名那里去匹配。 这样简化了记忆,也简化了书写:

比如我们经常使用的查看历史记录的命令, git log ...balabala  后面一大堆,那么可以用别名呀:

Git 从安装到使用学习记录

配置别名:

git config --global alias.别名 <别名替代的命令> 
git config  alias.别名 <别名替代的命令> 

加上 --global 表示对当前用户起作用,当前用于在 c:/users/username/.gitconfig 中可以查看; 另外,如果是针对用户的别名, 这个别名配置也是保存在 .gitconfig 这个文件中:

Git 从安装到使用学习记录

如果不加 --global , 表示别名只针对当前仓库, 配置的别名保存在 当前仓库的 .git/config 文件中 :

Git 从安装到使用学习记录

 

OK,这篇博文就记录到这里,如果哪位同学碰到其中有错误的地方,,请高抬贵手帮忙给我评论指出来,感激不尽!!

另外:下面是我学习过程中参考的链接,主要是看廖雪峰老师的git教程:

官网的git book : https://git-scm.com/book/zh/v2

廖雪峰老师的教程: https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

易佰git教程: https://www.yiibai.com/git

git安装教程参考这位老哥: https://blog.csdn.net/q563573095/article/details/79558067