Git分布式版本控制系统 企业高校持续集成平台场景介绍 何为Git Git与SVN的区别 Git的基本设计理念 Git的精髓——分支 分支合并,变基 Git的windows和Linux软件包下载链接 Windows上Git安装 Linux上yum安装Git Linux上源码包安装Git Git的命令入门 Git帮助文档 git init初始化git工作目录 创建github账号,并创建个人github远程仓库 git remote用于管理远程仓库并添加 git clone克隆一个现有的仓库到本地(在GitB主机测试) git fetch将远程仓库的变更拉去到本地仓库(GitA主机) git pull将远程仓库的变更拉取到本地仓库,并更新本地工作目录 git mv && git reset暂存区文件的修改和撤销 git diff文件对比利器 git log查看git提交历史记录 追根溯源给git log Git标签的使用 gitignore文件 Git分支管理 Git本地分支管理 本地分支的合并与删

 

何为Git

Git简单的来说,是一种分布式的版本管理工具,其具有以下优点:

  • 1、速度快

  • 2、简单的设计

  • 3、对非线性开发模式的强力支持(可以同时允许几千个分支同时进行开发和切换)

  • 4、完全分布式(防止集中式版本管理工具所出现的单点故障问题)

 

本地版本控制系统

许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间以示区别,这么做唯一的好处就是简单,不过坏处也步少,有时候回混淆所在的工作目录,一旦弄错文件丢了数据就没法撤销恢复

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

 

集中化的版本控制系统

接下来人们又遇到一个问题,如何让在不同系统上的开发者协同工作?于是,集中化的版本控制系统(Centralized Version Control Systems,简称 CVCS)应运而生.这类系统,诸如CVS,Subversion以及PerForce等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新,多年以来,这已成为版本控制系统的标准做法

 

分布式版本控制系统

于是分布式版本控制系统(Distributed Version Control System 简称 DVCS)面世了.在这类系统中,像Git,Mercural,Bazaar以及Darcs等,客户端并不只是提取最新版本的文件快照,而是把原始的代码仓库完整地镜像下来.这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复,因为每一次的提取操作,实际上都是一次对代码仓库的完整备份


 

实际的例子

以前我所在的小组使用SVN作为版本控制工具,当我正在试图增强一个模块,工作做到一半,由于会改变原模块的行为导致代码服务器上许多测试的失败,所以并没有提交代码.这时候上级对我说,现在有一个紧急的Bug需要处理,必须在两个小时内完成,我只好讲本地的所有修改diff,并输出成为一个patch文件,然后回滚有关当前任务的所有代码,再开始修改Bug任务,等到修改好后,再将patch应用回来,前前后后需要完成多个繁琐的步骤,这还不计中间代码发生冲突所要进行的工作量

可是如果使用Git,我们只需要开一个分支或者转回到主分支上,就可以随时开始Bug修改的任务,完成之后,只要切换原来的分支就可以优雅的继续以前的任务.只要你愿意,每一个新的任务都可以开一个分支,完成后,再将它合并到主分支上,轻松而优雅

因此,分布式的版本控制系统,再每个使用者电脑上就有一个完整的数据仓库,没有网络依旧可以使用Git,当然为了给习惯及团队写作,会将本地数据同步到Git服务器或者GitHub等远程代码仓库

 

公有的Git远程仓库

https://github.com/

 

Git与SVN的区别

Git与SVN是目前大多数企业所选择的版本管理工具,两者也代表了版本管理的两个主要的设计模式和理念。SVN是集中式版本管理系统的代表,*代码库存储着所有代码提交者的代码,而每个项目的参与者只负责代码的提交,*代码库则保存着完整版的所有代码。但这也造成了一系列的问题:

  • 1、*代码库单点故障所带来的项目风险,并且一旦发生,代码则无法恢复。

  • 2、提交代码时由于网络带宽问题所带来时间上的延迟,影响开发人员的工作效率。

  • 3、对于*代码库而言,其服务器压力过大,数据库容量暴增。

Git则是建立在本地库基础之上的分布式版本管理工具,最终可以使得任何代码的提交者都可以成为“*代码库”。Git的根本思想和基本工作原理主要是在本地复制一个“代码库”,每次提交的代码均是推送到本地代码库中,节约了由于网络带宽所带来的限制,不至于出现提交5MB的代码而需等待20分钟的情况。另一方面,一旦*代码库的服务器出现“崩溃”,那么任何“本地库”均可以还原*代码库。

 

Linux是如何通过Git来实现这个目标的呢?

Git的核心思想在于,每次代码版本的更迭和变化,Git都会记录数据文件的整体是否发生变化,而大多数其他系统则只关心文件内容的具体差异变化,这类系统每次记录有哪些文件作了更新,以及都更新了哪些行的什么内容。

Git并不保存这些前后变化的差异数据。实际上,Git更像是把变化的文件快照后,记录在一个微型的文件系统中。每次提交更新时,它会纵览一遍所有文件的指纹信息并对文件一一作快照,然后保存一个指向这次快照的索引。为提高性能,若文件没有变化,Git不会再次保存,而只是对上一次保存的快照作一链接。

总的来说,Git是一个存储着整个代码快照或者代码快照链接的小型文件系统,所以在每次代码修改之后都能够保持整个代码库的“风貌”,而不是像其他版本管理系统一样,只记录修改的文件和具体的修改内容。要复原整个代码库的话,还需借助“原始材料”。

 

Git的基本设计理念

 

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

在Git中的绝大多数操作都只需要访问本地文件和资源,不用联网。如查看提交记录、修改内容信息、版本更新、建立分支、切换分支等等。因为Git在本地磁盘上就保存着所有当前项目的历史更新,所以处理起来速度飞快。例如,你如果想要查看现在的代码和一个月前的版本有何差异,那么Git会取出一个月前的代码快照和此时的代码做一次对比,而不用请求远程服务器来做这件事,或者是把老版本的代码拉到本地作比较。

如果是SVN的话,那么你必须在有网络的情况下才能够提交代码,而此时你现在在火车上,那么你无法做任何事情,然而如果你正在使用Git,那么你可以随时的提交已经测试通过的代码模块,等到有网络的时候再上传到远程仓库即可。

 

时刻保持数据的完整性

Git通过对管理起来的每个文件计算Hash值,从而得到每个数据的唯一标识和索引。在Git中也全靠这些Hash值来唯一识别文件,而不是文件名。该“指纹”Hash值是一个由40位16进制字符串组成的,任何文件的损坏或者数据缺失都会被Git通过Hash值校验轻松识别到。

 

Git的三个文件区域

对任何一被Git管理的文件而言,其只具有三种可能的状态,分别是“已提交”,“已修改”和“已暂存”。已提交表示该文件已经被安全保存在本地数据库中了;已修改表示此文件修改了,但没有提交保存;已暂存表示已经把修改后的文件提交到了暂存区域但还没有提交。

 

Git的精髓——分支

分支是Git的核心所在,犹如操作系统的内核对于操作系统而言至关重要,也是Git能够支持上千个分支并发处理的关键所在。为了要理解Git分支的本质思想,我们需要结合Git的保存数据的方式来仔细讲解,Git保存的不是文件差异或者变化量,而只是一系列文件快照,理解这点很关键。

在Git提交时,会保存一个提交(commit)对象,这个commit对象包含着以下内容:

  • 1、指向暂存内容快照的指针。

  • 2、本次提交的作者等相关附属信息。

  • 3、零个或多个指向该提交对象的父对象指针(普通提交只有一个父亲,如果从多个分支合并而来则有多个父亲)。

讲完这些之后,我们再回过头来谈Git的分支。Git中的分支,其实本质上仅仅是指向commit提交对象的可变指针,它在每次提交的时候,都会自动向前移动。新建一个新的分支只是在当前commit对象上再创建一个新的可变指针;Git会保存一个名为HEAD的特别指针,指向分支的可变指针,HEAD表示当前分支。

 

分支合并,变基

分支合并不是简单地把分支指针右移,而是对三方合并后的结果重新做一个新的快照,并自动创建一个指向它的提交对象。这个提交对象。这个提交对象比较特殊,它有两个祖先。在分支合并的时候,可能会导致冲突的发生,需要人工解决冲突才能够重新提交代码。

分支变基指的是回到两个分支最近的共同祖先,根据当前分支后续的历次提交对象,生成一系列的文件补丁,然后在基底分支的基础之上,逐个应用之前准备好的补丁文件,最后会生成一个新的合并提交对象。切勿对已发布版本的代码进行变基操作。

 

Git的windows和Linux软件包下载链接

链接:https://pan.baidu.com/s/1CHZpkPlGRDuA0nPGqMYJcg 
提取码:cjj6

 

Windows上Git安装

Windows客户端下载地址:https://www.git-scm.com/downloads

双击安装包一路下一步即可

在桌面上创建一个文件夹

在文件夹右键选择Git Bash Here 进入git命令界面

到此我们windows的git客户端就安装完成了

 

Linux上yum安装Git

 

安装环境查看

cat /etc/redhat-release

uname -r

 

安装git客户端

yum -y install git

which git

git --version

 

git全局配置

git config --global user.name "Mr.sun" --->配置git使用用户

git config --global user.email "1123400300@qq.com" --->配置git使用邮箱

git config --global color.ui true --->语法高亮

git config --list --->查看全局配置

 

回滚yum安装过的Git

yum -y history

yum history undo IP号

which git


 

Linux上源码包安装Git

yum -y install curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc perl-ExtUtils-MakeMaker

rpm -qa curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc perl-ExtUtils-MakeMaker

tar xf git-2.9.5.tar -C /usr/src

cd /usr/src/git-2.9.5

./configure --prefix=/usr/local/git

make && make install

ln -sf /usr/local/git/bin/* /usr/bin

which git



 

源码编译需要链接git的命令库

ln -s /usr/libexec/git-core/* /usr/bin

git --version

至此,利用源码包安装Linux操作系统的git客户端就安装好了

 

Git的命令入门

工作区(放代码目录) 
你建立的本地git项目目录

暂存区(git add) 
将工作区里变更部分(与上一版本不同的部分)暂时存储起来的地方

本地仓库(git commit) 
在本地创建的git版本仓库,用于提交工作区的变更

远程仓库(git push) 
githab,gitlab或者队友机器上所建立的一个仓库

主机 IP 备注
GitA 192.168.200.70 Git测试服务器
GitB 192.168.200.90 Git测试服务器
 

Git帮助文档

LANG=zh_CN.UTF8 --->当前界面生效中文模式

git

 

git init初始化git工作目录

 

在linux上

mkdir -p /mycode

cd /mycode

git init

ls -la

 

git add将变更添加进入暂存区

touch test.txt

git add test.txt

 

查看git工作目录的暂存区状态

git status

 

git commit将变更从暂存区提交到本地仓库

git commit -m "test.txt" 
会提示你告诉它你是谁才让提交

 

注册自己的个人信息并再次提交(已经注册过个人信息了所以这里没提示)

git config --global user.name "Mr.sun"

git config --global user.email "1123400300@qq.com"

git commit -m "test.txt"


 

创建github账号,并创建个人github远程仓库

https://github.com/

https://github.com/linyaonie/yunjisuan.git




 

git remote用于管理远程仓库并添加

git remote -v --->查看远程仓库

git remote add 代号 URL --->origin是默认代号

git remote add test https://github.com/linyaonie/yunjisuan.git

 

git push将本地仓库的变更推送到远程仓库的某个分支

git push -u test master --->test是代号,master是分支名字

git push https://github.com/linyaonie/yunjisuan.git master --->没有设置代号也可以直接URL

需要输入github仓库账号和密码

 

重新回到github网站刷新一下就会看到推送的分支

https://github.com/linyaonie/yunjisuan

 

git clone克隆一个现有的仓库到本地(在GitB主机测试)

我们在另一台GitB上来模拟其他客户端进行远程仓库到本地仓库的操作

 

首先yum安装git命令

yum -y install git

which git

 

创建项目目录并克隆

mkdir /mycode

cd /mycode

git clone https://github.com/linyaonie/yunjisuan.git master

cd master

ls

 

修改仓库里的文件内容,并提交变更到本地,推送变更到远程仓库

echo "welcome" >> test.txt

git status

 

将变更加入缓存区

git add test.txt

 

将缓存区的变更提交到本地仓库(需要先注册个人信息)

git config --global user.email "1123400300.qq.com"

git config --global user.name "Mr.sun"

git commit -m "ceshi.txt"

 

将本地仓库代码推送到远程仓库

git push -u origin master

输入邮箱和密码进行推送

 

浏览器打开github查看提交情况

https://github.com/linyaonie/yunjisuan

 

git fetch将远程仓库的变更拉去到本地仓库(GitA主机)

git fetch -u test master

git status

 

git checkout检查工作目录代码与本地仓库中的代码的差异

git checkout

 

git merge将远程仓库变更,更新到本地工作目录中

git merge test/master

cat test.txt

 

git pull将远程仓库的变更拉取到本地仓库,并更新本地工作目录

git pull = git fetch + git merge --->有版本冲突只有简介的方式才能修改,pull是没办法修改冲突的

 

在GitA上对文件进行改动,并推送到github远程仓库

echo "yunjisuan" >> test.txt

cat test.txt

git add *

git commit -m "GitA修改了test.txt"

git push -u test master

输入github邮箱和密码并进行上传

 

在GitB上,拉取远程仓库的变更后直接合并进本地仓库的master分支

git remote -v

git pull origin master

cat test.txt

 

git mv && git reset暂存区文件的修改和撤销

如果文件还没有被添加到暂存区,那么Linux命令直接改名即可

git status

touch bennet.txt

git status

mv benet.txt yunjisuan.txt

git status

ls

 

假如变动的文件已经添加到了暂存区(如果直接mv改名,则需要把删除的文件git rm 文件名删除掉)

ls

git add *

git mv yunjisuan.txt benet.txt

git status

ls

 

通过git reset来给已经添加到暂存区的文件撤销掉

git status

git reset benet.txt

git status

 

git diff文件对比利器

git diff命令可以将本地的工作目录中的文件与本地仓库的文件进行对比

echo "ceshi" >> test.txt

git diff test.txt

 

git log查看git提交历史记录

git log -2 --->查看最后2条记录

git log -p -1 --->-p显示每次提交的内容差异

git log --stat -2 --->--stat简要显示数据增改行数,这样就能看到提交中修改过的内容

git log --pretty=oneline --->一行显示提交的历史记录


 

追根溯源给git log

 

Git还原历史数据

git服务程序中有一个叫做HEAD的版本指针,当用户申请还原数据时,其实就是将HEAD指针指向某个特定的提交版本,但是因为git是分布式版本控制系统,为了避免历史记录冲突,故使用了SHA-1计算出十六进制的哈西字符串区分每个提交版本,另外默认的HEAD版本指针会指向到最近一次的提交版本记录,而上一个提交版本会叫HEAD^,上上一个版本则会叫HEAD^^,当然一般会用HEAD~5来表示往上数第五个提交版本

git reset --hard HEAD^ --->还原历史提交版本上一次

git reset --hard 3de15d4 --->找到历史还原点的SHA-1值后,就可以还原(值不写全,系统会自动匹配)

 

修改一个文件,并提交到本地仓库

ls

echo "xin" >> bennet.txt

git add *

git commit -m "benet.txt添加了内容"

 

查看历史提交记录,并回滚到上一个提交的版本

git log --pretty=oneline

 

回滚到前一个版本并查看之前改动的文件

git reset --hard HEAD^

git log --pretty=oneline

cat benet.txt

 

回滚到指定提交的版本

git log --pretty=oneline

git reset --hard 号

git log --pretty=oneline

 

Git还原未来数据

当我们回滚历史某个提交版本了以后 
我们发现我们已经没有在那个版本之后的提交记录了 
也就是说,我们一旦还原了历史版本,想要再次还原回去,那么就回不去了 
如此一来,一旦错了,我们怎么办

 

git reflog查看未来历史更新点(所有历史数据)

git reflog

 

还原之前的版本

git reset --hard 号

git log --pretty=oneline

 

Git标签的使用

前面回滚使用的是一串字符串,又长又难记 
git tag 标签 -m "描述" 
每次提交都可以打一个标签

git tag v1.0 --->给当前提交的内容打一个标记(方便回滚)

git tag --->查看当前所有标签

git show v1.0 --->查看当前1.0版本的详细信息

git tag v1.2 -m "描述"

git tag -d v1.0 --->删除之前的v1.0标签

 

查看所有标记

git tag

 

添加v1.0标签给当前提交的内容

git tag v1.0

 

查看标签为v1.0的提交的详细信息

git show v1.0

 

修改bennet文件内容,再次进行提交

cat benet.txt

echo "ceshi" >> benet.txt

git add *

git commit -m "benet.txt添加了内容并测试标签"

 

给本次提交添加v2.0标签

git tag v2.0

git tag

 

查看标签为v1.0的提交的详细变更内容

git show v1.0

 

查看标签为v2.0的提交的详细变更内容

git show v2.0

 

删除v2.0标签,重新设定附带描述信息的标签

git tag -d v2.0

git tag

git tag v2.0 -m "给文件benet.txt增加一行代码"

git tag

git show v2.0

 

通过标签进行历史提交回滚,回滚到v1.0的版本

cat benet.txt

git reset --hard v1.0

cat benet.txt

 

gitignore文件

为什么使用.gitignore文件

大量与项目无关的文件全推到远程仓库上,同步的时候会非常慢,且跟编辑器相关的一些配置推上去之后,别人更新也会收到影响.所以,我们使用该文件,对不必要的文件进行忽略,使其不被git追踪.

一般情况下,.gitignore文件,在项目一开始创建的时候就创建,并推送到远程服务器上.这样大家初次同步项目的时候,就会用到该文件,避免以后,团队成员把与项目无关的文件,传到远程服务器上

gitinore文件匹配规则

  • *.log 表示忽略项目中所有以.log结尾的文件

  • 123?.log 表示忽略项目中所有以123加任意一个字符的文件

  • /error.log 表示忽略根目录下的error.log文件

  • **/java/ 匹配所有java目录下的所有文件

  • !/error.log 表示在前面的匹配规则中,被忽略了的文件,你不想它被忽略,那么久可以在文件前加叹号

 

添加.gitignore文件并上传到远程仓库(上传远程仓库是为了让克隆远程仓库的人,能直接有过滤的目录)

vim .gitignore

cat .gitignore

 
  1. target
  2. *.log
  3. ?.idea

git add .gitignore

git commit -m "提交gitignore"

git push test master

 

在GitB主机上重新克隆并创建测试文件和测试

rm -rf /mycode

mkdir /mycode

cd /mycode

git clone https://github.com/linyaonie/yunjisuan.git master

cd master

ls -la

touch 111.log

touch 666

git status

 

Git分支管理

 

分支的结构概述

在实际的项目开发中,尽量保证master分支稳定,仅用于发布新版本,平时不要随便直接修改里面的数据文件,那么工作都在dev分支上,每个人从dev分支创建自己个人分支,开发完合并到dev分支,最后dev分支合并到master分支

所以,团队的合作分支看起来会像下图的样子

分支管理工作流程

在工作中,为了保证master分支稳定,产品经历通常会从master分支上复制一份代码作为dev分支 
然后成员开发A在从dev分支上复制一份代码叫做michael 
然后成员开发B在从dev分支上复制一份代码叫做bob 
当一个新功能开发完毕,或者一个bug修复完毕以后.开发人员会先将代码变更推送到自己的个人分支,然后再把个人分支的变更合并到dev分支里 
当开发经历和测试人员拉取dev分支的代码进行测试以后,如果没问题,那么开发经历就会把dev分支的变更合并进master版本 
最后,由于master版本新增了测试过的新功能,那么就需要进行项目发布或者代码上线了

 

Git本地分支管理

 

本地分支的创建与切换

git branch --->查看当前分支情况,当前分支前有*号

git branch linux --->创建分支

git checkout --->检查本地分支与远程分支的变更差异

git checkout linux --->切换分支

 

检查当前分支情况并创建分支和切换分支

git branch

git branch linux

git checkout linux

git branch

 

尝试在linux本地分支进行代码提交

git branch

cat benet.txt

echo "yunjisuan" >> benet.txt

git add *

git commit -m "linux分支第一次提交"

git checkout master

cat benet.txt

 

把代码放到暂存区,切换分支(切换分支的时候要清空暂存区,或者提交完在切换,分支公用一个暂存区)

git branch

git checkout linux

touch linux.txt

git add *

git status

git checkout master

git status

git checkout linux

git commit -m "linux分支第二次提交"

git checkout master

git status


 

本地分支的合并与删除

想把linux的工作成功合并到master分支上 
先切换到master分支 
git merge linux --->合并linux分支到master 
git branch -d linux --->确定合并完成后,可以放心的删除linux分支

 

自动合并本地分支(合并的时候master不能改变,否则合并会出问题)

git branch

cat benet.txt

git merge linux

cat benet.txt

 

本地分支的删除

git branch -d linux --->假如分支的变更没有合并到当前分支,那么必须用-D参数强制删除分支

git branch

 

手动合并本地分支===>本地分支代码冲突解决方案

当本地分支之间的同名目录-同名文件-同一行内容不同时,在进行分支合并时就会产生冲突,故为了解决代码冲突,就需要人工手动合并 
在工作中,为了进来避免冲突,一般开发人员之间尽可能不负责相同的功能模块,也就不至于同时修改同一个文件

 

在GitA上进行操作,让linux分支和master分支产生文件代码冲突

git branch

git branch linux

git checkout linux

ls

echo "linux" >> linux.txt

cat linux.txt

git add *

git commit -m "linux提交"

git status

 

切换到master

git checkout master

echo "master" >> linux.txt

cat linux.txt

git add *

git commit -m "master提交"

git status

 

GitA上master进行合并linux分支

git branch

git merge linux

vim linux

 
  1. <<<<<<< HEAD --->表示当前所在的分支
  2. master --->此行表示当前所在分支本行的master和下边的linux所在分支的linux冲突
  3. ======= --->隔离符号
  4. linux --->和上边的master内容冲突
  5. >>>>>>> linux --->linux分支

手动排除,选择保留后的内容,假如我们要保留linux分支的内容,然后再将工作目录中的变更提交即可人工解决代码冲突,并完成分支合并



 

修改完分支冲突在提交并删除分支

cat linux.txt

git add *

git commit -m "修改了一个分支冲突"

git status


 

git远程分支管理

将linux本地分支代码和标签推送到github远程仓库的linux分支

 

在GitA上,创建本地分支linux,复制master代码

git branch

git branch linux

git checkout linux

ls

 

将工作目录代码benet.txt文件修改后提交到本地linux分支

echo "远程分支提交测试" >> benet.txt

cat benet.txt

git add *

git commit -m "远程测试"

git status

 

将本地linux分支推送到远程github的linux分支

git push test linux

输入邮箱和密码


 

创建本地标签,并推送到githud

git tag v3.0 -m "测试"

git tag

git push test v3.0

输入邮箱和密码

 

浏览器访问

https://github.com/linyaonie/linux/v3.0

 

在GitA上简单创建一个没有web界面的git远程服务器的本地仓库

useradd git

echo "linyaonie" | passwd --stdin git

su - git

cd /home/git

pwd

mkdir repos

cd repos

mkdir dev yunjisuan

cd yunjisuan

git --bare init --->--bare加上这个参数这个目录就只能当仓库使,就不能代码提交了

pwd

/home/git/repos/yunjisuan --->仓库链接地址

 

在GitB上创建目录并克隆

mkdir /test

cd /test

git clone git@192.168.200.70:/home/git/repos/yunjisuan

输入密码并克隆,因为创建的目录里面没有任何东西,所以提示是一个空版本库

 

在测试目录下创建文件并生成git远程仓库

ls

cd yunjisuan

touch test.txt

git add *

git commit -m "仓库"

git remote -v

git push -u origin master

 

因为总是需要输入密码,所以最好做一个免密钥

ssh-keygen

ssh-copy-id -i ~/.shh/id_ras.pud git@192.168.200.70

 

把测试目录删除并重新克隆进行测试

rm -rf /test

mkdir /test

cd /test

git clone git@192.168.200.70:/home/git/repos/yunjisuan

ls

cd yunjisuan

ls

这时候一个没有web界面的,远程服务器的本地git仓库就搭建完成了