Linus一直痛恨的CVS及SVN都是集中式的版本控制系统,而Git是分布式版本控制系统,集中式和分布式版本控制系统有什么区别呢?
先说集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。
集中式版本控制系统最大的毛病就是必须联网才能工作,如果在局域网内还好,带宽够大,速度够快,可如果在互联网上,遇到网速慢的话,可能提交一个10M的文件就需要5分钟,这还不得把人给憋死啊。
那分布式版本控制系统与集中式版本控制系统有何不同呢?首先,分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。
在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
当然,Git的优势不单是不必联网这么简单,后面我们还会看到Git极其强大的分支管理,把SVN等远远抛在了后面。
CVS作为最早的开源而且免费的集中式版本控制系统,直到现在还有不少人在用。由于CVS自身设计的问题,会造成提交文件不完整,版本库莫名其妙损坏的情况。同样是开源而且免费的SVN修正了CVS的一些稳定性问题,是目前用得最多的集中式版本库控制系统。
除了免费的外,还有收费的集中式版本控制系统,比如IBM的ClearCase(以前是Rational公司的,被IBM收购了),特点是安装比Windows还大,运行比蜗牛还慢,能用ClearCase的一般是世界500强,他们有个共同的特点是财大气粗,或者人傻钱多。
微软自己也有一个集中式版本控制系统叫VSS,集成在Visual Studio中。由于其反人类的设计,连微软自己都不好意思用了。
分布式版本控制系统除了Git以及促使Git诞生的BitKeeper外,还有类似Git的Mercurial和Bazaar等。这些分布式版本控制系统各有特点,但最快、最简单也最流行的依然是Git!
yum -y install git
//安装git软件包(一般自带),或者源码编译新版本(源码编译时,注意安装curl-devel软件包)
点击下载git-2.19.0.tar.xz的源码包
yum -y install perl-ExtUtils-MakeMaker gettext-devel expat-devel curl-devel zlib-devel openssl-devel openssl-devel gcc-c++ make //安装依赖包
tar -Jxvf git-2.19.0.tar.xz -C /usr/src/
cd /usr/src/git-2.19.0/
make prefix=/usr/local/git all //编译所有模块
make prefix=/usr/local/git install //安装
echo "export PATH=$PATH:/usr/local/git/bin">> /etc/profile //将命令添加到环境变量
yum -y erase git //卸载yum安装的git
source /etc/profile //重新读取环境变量文件使之生效
git --version //验证git是否为源码编译版本
git config --global user.name用户名 //设置用户名
git config --global user.email 邮箱地址 //设置邮箱
git config –list //查看git配置
注:也可通过"vim ~/.gitconfig"指定用户名及邮箱
git config --global --unset user.name 用户名 //如果有多个用户,想删除指定的用户可以使用
git init //在当前目录,初始化本地仓库,也可在`git init`后面添加指定的目录
例:
vim /opt/git/Demo.txt //在本地工作目录下新建文件
第一次
git add 文件路径
例:
git status //查看当前仓库文件状态(可以看出,没有提交和新增文件,但有跟踪到新文件)
git add Demo.txt //将文件提交到暂存区
git status //再次验证后,文件状态发生改变
git commit -m "文字说明"
例:
git commit -m “第一次提交” //将所有暂存区内容提交到仓库
git status //再次查看仓库状态后,可以看见无任何内容
注:所有新增或更改的文件都会先放在暂存区,但确认无误时,在使用commit提交(这样的好处在于,如果更改错误随时可以回退)
例:
vim /opt/git/Demo.txt //测试,修改下文件内容
第一次
第二次
git status //查看仓库状态后,可以看见检测到文件发生更改,但没有新增和提交
①确实需要修改,那么我们使用git add将文件放进暂存区
②如果是误修改,我们可以将文件回滚到之前的版本
git diff 文件 //查看文件变动情况
例:
git diff Demo.txt //查看文件更改情况,显示新增第二行内容
git checkout 文件 //撤销指定文件修改(未提交到暂存区前)
例:
cat Demo.txt //查看当前文件内容
git checkout Demo.txt //撤销文件修改
git status //仓库状态查看后,无内容
cat Demo.txt //再次验证文件内容,证明文件撤销成功
如果修改的文件已提交到缓存区
git reset HEAD 文件 //取消指定文件的暂存区修改(再使用checkout即可)
例:
cat Demo.txt //查看当前文件内容
vim /opt/git/Demo.txt //测试,修改下文件内容
第一次
第二次
git status //查看仓库状态后,可以看见检测到文件发生更改,但没有新增和提交
git add Demo.txt //将文件修改提交到暂存区
git status //再次验证后,文件状态发生改变
git checkout Demo.txt //撤销文件修改
cat Demo.txt //验证结果,撤销失败
git reset HEAD Demo.txt //取消Demo.txt文件暂存区的更改
git status //查看仓库状态后,可以看见检测到文件发生更改,但没有新增和提交(代表新增操作还原)
git checkout Demo.txt //再次执行撤销文件操作
cat Demo.txt //验证结果,撤销成功
当git init初始化git仓库之后,在文件夹中会多出一个.git隐藏文件夹,这个.git隐藏文件夹就是git的版本库repository
创建Git仓库的文件夹就是工作区working directory
暂存区:暂存区可以理解为一个虚拟工作区,这个虚拟工作区会跟踪工作区的文件变化(增删改等操作),工作区的位于.git文件夹下的index目录下
当需要对工作区的修改提交到版本库前,暂存区会与工作区进行差异比较,如果工作区与暂存区的文件不一致,那么需要同步工作区的修改到暂存区,然后才可以提交到版本库
暂存区可以说是工作区和版本库的桥梁,我们对文件的修改可以先放在暂存区中,如果后悔了不仅可以非常方便撤销,而且不会影响到现有的版本库
只要我们使用过git add,那么文件就会被跟踪,暂存区跟踪记录了工作区的文件名和文件状态(在index文件中会记录修改时间,文件大小等信息),当下次对文件进行修改的时候,会比较时间戳来判断文件是否被修改
并且在执行git status时,首先会到.git/index下查看被跟踪的工作区文件的时间戳,如果发现自上次执行git add(执行git add可以让工作区的文件被跟踪)以来,文件的时间戳发生了变化,那么判断文件发生了改动,于是会与暂存区的原始文件与工作区中的该文件进行差异比较,如果发现两个文件内容不一致,那么就给出差异信息
cd /opt/git //进入工作目录
touch newfile.txt //创建空文件
vim Demo.txt //修改已提交暂存区的文件内容
第一次
第二次
git status //查看当前仓库状态
git diff //查看暂存区和工作区文件差异
git add newfile.txt Demo.txt //将指定两个文件添加到暂存区
git status //再次查看当前仓库状态
git diff //这时再次比对暂存区和工作区差异,无区别
git commit -m “第二次更改” //将暂存区所有文件提交
git status //再次查看仓库暂存区状态,无内容
git log //查询所有提交的历史文件commit id、作者以及提交时间、提交信息但是不包括之前删除的历史记录
git log --pretty=oneline //只查询所有提交文件的commit id
git log --pretty=oneline 文件名 //查询指定某个文件的commit id
git reflog
git reset 版本ID //回退到指定版本(版本id可通过git relog查看)
例:
git reflog //查看所有提交文件版本id
git reset fc3523e //回退到指定版本id时的状态
git status //查看仓库状态
git checkout Demo.txt //撤销Demo.txt文件修改
cat Demo.txt //验证结果,回滚成功
例:
rm -rf Demo.txt //模拟文件删除
ls //验证文件是否删除
git status //仓库状态更改
git checkout Demo.txt //撤销Demo.txt文件修改操作
git status //再次查看仓库状态
ls //验证文件是否还原
cat Demo.txt //验证结果,还原成功
git rm 文件 //从仓库中删除指定文件
例:
ls //查看文件
git rm Demo.txt //从仓库中删除Demo.txt
git commit -m “删除Demo.txt文件” //提交删除操作到仓库
ls //验证文件是否删除
ssh-keygen -t rsa -C "邮箱地址"
例:
ssh-keygen -t rsa -C “GitHub注册邮箱” //本地生成rsa算法的私钥及公钥文件,-C指定标识名称
git clone https://github.com/CallousMaster/callousmaster.github.io.git
如出现:“fatal: HTTP request failed”,则有可能是git版本太低,需源码安装高版本。详情见开头的源码安装Git
如出现:"fatal: unable to access ‘https://github.com/CallousMaster/callousmaster.github.io.git/’: SSL connect error ",需更新系统软件包
wget -O /etc/yum.repos.d/CentOS-Base.repohttp://mirrors.aliyun.com/repo/Centos-6.repo //下载在线源
yum -y update //更新系统系统所有包
reboot //重启后,即可正常使用
vim demo.txt //在仓库下新增文件
第一次提交GitHub
git add demo.txt //将文件添加到暂存区
git commit -m “第一次更改” //将暂存区内容提交到本地仓库
git status //仓库状态查看后,提示需提交到远程仓库
git remote add first https://github.com/CallousMaster/callousmaster.github.io.git //在本地仓库添加一个远程仓库,后面的地址是远程仓库的地址,first为远程仓库标识名称可自定义
git push -u first master //将本地仓库内容提交到远程仓库master分支(第一次-u必须使用,之后提交操作可以忽略),注意输入用户名、密码
可以使用命令**git remote rm first
删除关联的远程仓库**
使用**git remote show first
来查看first远程仓库的具体分支**
使用**git remote –v
来查看与当前本地仓库相关联的远程仓库**
例:
git remote -v
git remote rm origin //删除名称为origin的远程仓库链接
git remote -v
git remote show first //查看指定远程仓库信息
vim demo.txt //在仓库下新增文件
第一次提交GitHub
第二次提交GitHub
git add demo.txt //将文件添加到暂存区
git commit -m “第二次修改”
git push first master //将本地仓库内容提交到远程仓库master分支
Master 是主分支,主要作为程序的发布,可以理解为是项目的最终版本,所以不能在master上进行开发,所以应该建立子分支进行开发
团队中多个人开发一下项目,一同事在开发一个新的功能,需要一周时间完成,他写了其中的50%还没有写完,如果他提交了这个版本,那么团队中的其它人就不能继续开发了,但是等到他全部写完再全部提交,又存在每天进度丢失的风险,这如何是好呢?
对于上面的这个问题,我们就可以用分支管理的办法来解决,一同事开发新功能他可以创建一个属于他自己的分支,其它同事暂时看不到,继续在开发分支(一般都有多个分支)上干活,他在自己的分支上干活,等他全部开发完成,再一次性的合并到主分支上,这样我们既可知道他的开发进度,又不影响大家干活
其他的版本控制器也有分支的概念,只不过切换,删除分支的时候非常慢、效率低下,而git切换或者删除分支几乎就是一瞬间的事
git branch //查看分支,默认只有一个master
git branch 分支名称
例:
git branch test //创建名称为test的新分支
git branch
git checkout 分支名称
例:
git checkout test //切换到test分支工作
git branch
git checkout -b 分支名称
例:
git checkout -b test2 //创建test2新分支并切换到该分支
git branch -d 分支名称
注:如果要删除的分支,正处于当前工作分支,必须切换到其余分支中才能删除
例:
git branch -d test //删除名为test分支
git branch
例:
git branch //查看当前所处分支
vim test2.txt //在test2分支下新建test2.txt文件
test2
git add test2.txt //将文件提交到暂存区
git commit -m “test2分支下新建文件” //将暂存区内容提交到本地仓库
git checkout master //切换到master分支
ls //验证后,发现test2分支文件不能查看
git merge test2 //将test2分支合并到当前分支
ls //合并分支后,文件新增
代码冲突如何产生的:当在分支上进行开发的时候,难免遇到别的开发人员和我们自己向仓库中提交相同的代码
比如有一个商城的项目,开发人员A和开发人员B都对同一段代码做了修改,当A进行提交后并push到远程仓库中master合并,B再进行提交并与远程仓库中的master进行合并这时候就会出现代码冲突
例:
git checkout test2 //切换到test2分支
vim test2.txt //编辑文件
test2
test2分支修改
git add test2.txt //添加文件到暂存区
git commit -m “test2分支修改” //将暂存区内容提交到test2分支
git checkout master //切换到master分支
vim test2.txt //master分支下,再次修改该文件
test2
主分支更改
git add test2.txt //添加更改到暂存区
git commit -m “master分支修改” //将暂存区内容提交到master分支
git merge test2 //将test2分支合并到当前分支
git status //仓库状态查看
cat test2.txt //查看合并后文件内容(这时能看见两个分支更改内容,将冲突删除或修改)
vim test2.txt //合并文件
test2
合并完毕
git add test2.txt //添加更改到暂存区
git commit -m “master解决冲突” //将暂存区内容提交到master分支
git merge test2 //将test2分支合并到当前分支
cat test2.txt //验证合并情况
标签就是版本库的一个快照,在发布新版本的时候,一般都会给老的版本打个标签,方便后续直接使用指定的版本
git tag //查询标签
git tag 标签名称 //创建标签
例:
git tag version1 //创建version标签(默认无标签)
git tag
git tag -a 标签名称 -m "描述信息" //新建标签,并添加描述信息
例:
git tag -a version2 -m “版本2” //新建version2标签,并添加描述信息
git tag
git tag 标签名称 commitID //给之前忘记打标签的文件,设置标签
例:
git log --pretty=oneline //查看当前分支所有已提交文件id
git tag version3 89c87e8f33aac869861a20928ec133862281a980 //给指定commit id创建标签
git show 标签名称 //查看标签信息
例:
git show version //查看version3标签信息
git tag -d 标签名称 //删除标签
例:
git tag//查看当前所有标签
git tag -d version2 //删除version2标签
git tag //验证标签是否删除
git push 远程仓库名 标签名称 //提交标签到远程仓库
例:
git push first version1 //将version1标签提交到远程仓库
git push 远程仓库名 --tags //提交所有版本号到远程仓库
例:
git push first --tags //提交本地仓库所有标签
例:
git tag -d version1 //删除本地version1标签
git push first :refs/tags/version1 //远程远程version1标签