P1 版本控制概述
关于版本控制
- 版本控制是一种记录若干文件内容变化,以便将来查阅特定版本修订情况的系统。
- 有了它你就可以将某个文件回溯到之前的状态,甚至将整个项目都退回到过去某个时间点的状态
- 可以比较文件的变化细节,查出是谁最后修改了什么地方,从而造成某些怪异问题,又是谁在何时报告了某个功能缺陷
本地版本控制系统
- 人们很久以前就开发了许多种本地版本控制系统
- 大多都是某种简单的数据库来记录文件的历次更新差异
- 其中最流行的一种叫做 rcs
- 它的工作原理基本上就是保存并管理文件补丁(patch)
#所有的项目版本都在本地服务器上,只能在本地从版本库中获取代码,无法协同工作。
集中化的版本控制系统
- 集中化的版本控制系统允许不同的开发者可以协同工作
- 此类系统有 CVS,Subversion 以及Perforce 等
- 它们都单一拥有集中管理的服务器,保存所有文件的修订版本
- 协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新
#1》所有的项目版本数据都存储在统一的服务器上;
#2》协同工作的人,都需要通过客户端远程连接到这台服务器上,取出文件或提交更新;
#3》服务器故障或断网情况下,无法使用;
分布式版本控制系统
- 客户端并不只提取最新版本的文件快照
- 而是把原始的代码仓库完整的镜像下来
- 任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复
- 每一次的提取操作,实际上都是一次对代码仓库的完整备份
Git 的历史
- Linux 内核开源项目有着为数众多的参与者
- 1991-2002年间,绝大多数 Linux 内核维护工作都花在提交补丁和保存归档的繁琐事务上
- 2002年,整个项目组开始启动分布式版本控制系统 BitKeeper 来管理和维护代码
- 到 2005 年的时候,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回来免费试用 BitKeeper 的权力
Git的特点
- 直接快照,而非比较差异
- 近乎所有操作都可本地执行
- 时刻保持数据完整性。在保存到 Git 之前,所有数据都要进行内容的校验和(checksum)计算,并将此结果作为数据的唯一标识和索引
Git 状态
- 任何一个文件,在 Git 内都只有三种状态**
- [x] 已提交(committed): 表示该文件已经被安全的保存在本地数据库中了
- [x] 已修改(modified): 表示修改了某个文件,但还没有提交保存
- [x] 已暂存(staged): 表示把已修改的文件放在下次提交时要保存的清单
工作区: #编写代码,工作的目录;
暂存区: #临时存储的区域,可以返回,重复修改;
版本库: #将暂存区中的文件,提交到版本库中,进行永久性存储;
安装及配置:Git 安装后需配置用户相关信息
pycharm主机,安装git,实现git命令的自动补全功能
[root@kube-node1 ~]# yum -y install git
[root@kube-node1 ~]# rpm -q bash-completion #git的命令补全通过 bash-completion实现,没有则需要安装
[root@kube-node1 ~]# source /etc/bash_completion.d/git #使用source 在当前解释器下加载git,让立刻生效,否则需要重启虚拟机
[root@kube-node1 ~]# git #git<空格>
可以列出git的可以使用的命令 [root@kube-node1 ~]# git config --global user.name 'MrZhangzhg' #指定提交代码或程序的作者
[root@kube-node1 ~]# git config --global user.email '[email protected]' #指定提交代码或程序的作者邮箱
[root@kube-node1 ~]# git config --global core.editor vim #指定使用git时的默认编译器为vim【例如编写提交日志信息时,自动使用vim】
[root@kube-node1 ~]# git config --list #查看git的全局配置信息
[root@kube-node1 ~]# cat ~/.gitconfig #git的全局配置信息存放在 ~/.gitconfig中
二、git基础应用
P1 管理仓库
创建仓库:尚不存在项目时,可以直接创建,在pycharm主机上操作
[root@kube-node1 ~]# mkdir git_lesson #创建目录,用于进行git的演示操作
[root@kube-node1 ~]# cd git_lesson/ #进入到目录下
[root@kube-node1 git_lesson]# git init devops #初始化一个空的git仓库 devops
在已有项目的目录中创建仓库
[root@kube-node1 git_lesson]# mkdir myweb #先创建一个目录
[root@kube-node1 git_lesson]# cd myweb/
[root@kube-node1 myweb]# echo '
My Test Web Site
' > index.html #创建一个文件,作为项目文件#在当前目录下进行,进行仓库的初始化,会将目录下的文件,加入到版本仓库中
[root@kube-node1 myweb]# git init
仓库说明
- 初始化后,在当前目录下会出现一个名为 .git 的目录
- 所有 Git 需要的数据和资源都存放在这个目录中
- 目前仅仅是按照既有的结构框架,初始化好了仓库中所有的文件和目录
- 还没有开始跟踪管理项目中的任何一个文件
还可以通过克隆现有仓库的方式获取版本库:直接克隆
[root@kube-node1 myweb]# cd ..
[root@kube-node1 git_lesson]# git clone https://github.com/schacon/grit
克隆时,指定本地目录
[root@kube-node1 git_lesson]# git clone https://github.com/schacon/grit mygrit
记录更新到仓库
文件状态
- 工作目录下的所有文件都不外乎这两种状态:已跟踪或未跟踪
- 已跟踪的文件是指被纳入版本控制管理的文件,在上次快照中有他们的记录,工作一段时间后,它们的状态可能是未更新,已修改或者已放入暂存区
- 所有其他文件都属于未跟踪文件
文件状态生命周期:工作区中文件状态的改变
#0》被版本库管理的文件称为【已跟踪文件】,否则为【未跟踪文件】;
#1》【未修改】、【已修改】和【暂存区内文件】都属于【已跟踪文件】;
#2》其他文件都属于未跟踪文件;
#3》【未跟踪文件】通过 'git add' 可以变为【已跟踪文件】;
#4》【未修改文件】通过 '编辑文件' 可以变为【已修改文件】;
#5》【已修改文件】通过 'git add' 可以变为【暂存区内文件】;
#6》【暂存区内文件】通过 'commit' 存入版本库,文件又变为【未修改文件】;
检查状态
- 干净的工作区:当前没有任何跟踪着的文件,也没有任何文件在上次提交后更改过
- 信息还表明,当前目录下没有出现任何处于未跟踪的新文件
- 该命令还显示了当前所在的分支是 master, 这是默认的分支名称
#进入到git的grip仓库下
[root@kube-node1 git_lesson]# cd /root/git_lesson/grit/
[root@kube-node1 grit]# git status #查看git仓库的状态,干净的工作区
未跟踪文件
- Git 不会自动将工作区中的文件纳入跟踪范围
- 这些文件就是 Untracked files
[root@kube-node1 ~]# cd /root/git_lesson/myweb/
[root@kube-node1 myweb]# ls #查看目录内容,'git init'不会将已存在的文件自动加入到版本库中
[root@kube-node1 myweb]# git status #查看工作区状态,index.html为未跟踪的文件
跟踪单个文件
[root@kube-node1 myweb]# git add index.html #将单个文件index.html添加到暂存区中
跟踪所有文件
[root@kube-node1 myweb]# vim README #在当前目录下添加新的文件
git test
[root@kube-node1 myweb]# git add . #将当前目录下的所有文件,都添加到暂存区中
[root@kube-node1 myweb]# git status #当前目录下所有文件都处于暂存区中
忽略文件
- 可以创建一个名为 .gitignore 的文件
- gitignore 的格式规范如下
- [x] 所有空行或者以注释符号 # 开头的行都会被 Git 忽略
- [x] 可以使用标准的 glob 模式匹配【支持通配符】
- [x] 匹配模式最后跟反斜杠(/)说明要忽略的是目录
- [x] 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号 ( !)取反
将某些文件设置为忽略文件,【git add】时,这些文件不会添加到暂存区
[root@kube-node1 myweb]# vim function.txt #创建文件function.txt,用于演示
用户注册
留言
支付
[root@kube-node1 myweb]# echo function.txt > .gitignore #将文件名function.txt,写入到 .gitignore【忽略文件】中
[root@kube-node1 myweb]# echo .gitignore >> .gitignore #将忽略文件本身.gitignore,也写入到 .gitignore中
[root@kube-node1 myweb]# git status #查看工作区状态,设置为【忽略文件】的数据,不会在此显示
[root@kube-node1 myweb]# git add .
[root@kube-node1 myweb]# git status #设置为【忽略文件】的数据,也不会被添加到暂存区中
提交更新:直接提交会启动文本编辑器以便输入本次提交的说明
#【git commit】 提交时,需要输入【版本说明信息】 ——》这里为'project init'
#使用的编辑器为已经定义好的:【git config --global core.editor vim】
[root@kube-node1 myweb]# git commit
[root@kube-node1 myweb]# git status #【暂存区】数据提交成功,文件状态变为未修改
也可以使用 -m 参数提交说明的方式,在一行命令中提交更新
[root@kube-node1 myweb]# vim README #修改文件README
#git test
this is a test
[root@kube-node1 myweb]# git add . #将当前目录下的所有文件,都添加到【暂存区】中
[root@kube-node1 myweb]# git commit -m 'modified README' #提交
移除文件
- 要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除 (确切地说,是从暂存区域移除),然后提交
- 用git rm 命令完成此项工作,并连带从工作目录中删除
[root@kube-node1 myweb]# git rm index.html #将index.html删除
[root@kube-node1 myweb]# git status #查看工作区状态,被删除的文件存在于暂存区【可以撤回】,commit提交后才会生效
移动文件,并进行重命名
[root@kube-node1 myweb]# git mv README README.md
[root@kube-node1 myweb]# git status
[root@kube-node1 myweb]# git commit -m 'rm index.html, mv README README.md' #提交
[root@kube-node1 myweb]# git status
查看提交历史
- 在提交了若干更新之后,又或者克隆了某个项目,回顾提交历史,使用 git log 命令
- 每次更新都有一个 SHA-1 校验和、作者名字和电子邮件地址、提交时间,最后缩进一个段落显示提交说明
[root@kube-node1 myweb]# git log
取消已暂存文件
- 文件修改后,错误的提交到暂存区
- 希望将文件撤出暂存区,但是保留其修改的内容
[root@kube-node1 myweb]# vim README.md #在README.md文件中,添加新的行
#git test
this is a test
```python
print("Hello World!")
```
[root@kube-node1 myweb]# git add . #将修改的文件提交到【暂存区】
[root@kube-node1 myweb]# git reset HEAD README.md #取消已暂存的文件README.md
[root@kube-node1 myweb]# vim README.md #可以对README.md中的文件继续进行编辑
#git test
this is a test
```python
print("Hello World!")
print("Hello Tedu!")
```
取消对文件的修改
- 文件修改后,后悔所做出的修改
- 希望文件恢复为修改前的内容
[root@kube-node1 myweb]# git checkout -- README.md #将版本库中的文件取出来,覆盖工作区的文件
[root@kube-node1 myweb]# cat README.md #工作区的修改都消失【谨慎操作】
三、git分支管理
P1 标签管理
标签概述
- 同大多数 VCS 一样,Git 也可以对某一时间点上的版本打上标签
- Git 可以给历史中的某一个提交打上标签,以示重要
- 在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做
- 发布一个版本时,通常先在版本库中打一个标签(tag),这样就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。
#对某一个重要的版本打上标签,任何时候,都可以将打标签的历史版本取出来
列出标签
- 在 Git 中列出已有的标签是非常简单直观的
- 这个命令以字母顺序列出标签;但是它们出现的顺序并不重要
查找标签:可以使用特定的模式查找标签
标签分类
- Git 使用两种主要类型的标签
- [x] 轻量标签(lightweight): 它只是一个特定提交的引用 ——》 指针指向该版本
- [x] 附注标签 ( annotated): 是存储在 Git 数据库中的一个完整对象。其中包含打标签者的名字、电子邮件地址、日期时间;还有一个标签信息;并且可以使用 GNU Privacy Guard (GPG) 签名与验证
附注标签
- 简单的方式是当你在运行 tag 命令时指定 -a 选项
轻量标签
- 创建轻量标签,不需要使用选项,只需要提供标签名字
[root@kube-node1 myweb]# git tag #列出已有的标签
给最近的版本打标签
[root@kube-node1 myweb]# git log #在日志中,查看版本信息
[root@kube-node1 myweb]# git tag 1.0 #tag 给最近的版本打轻量标签为 1.0
[root@kube-node1 myweb]# git tag #列出已有的标签
[root@kube-node1 myweb]# git tag v1.0 -m 'my version 1.0' #给最近的版本打附注标签
[root@kube-node1 myweb]# git tag
[root@kube-node1 myweb]# git show 1.0 #调出详细版本信息【包括做了哪些修改】
[root@kube-node1 myweb]# git show v1.0
删除标签:git tag -d < tagname >
[root@kube-node1 myweb]# git tag
[root@kube-node1 myweb]# git tag -d 1.0 #删除标签1.0
[root@kube-node1 myweb]# git tag
分支概述
- 几乎所有的版本控制系统都以某种形式支持分支
- 使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线
- 在很多版本控制系统中,这是一个略微低效的过程
- Git 处理分支的方式可谓是难以置信的轻量,创建新分支这一操作几乎能在瞬间完成
- 在不同分支之间的切换操作也是一样便捷
##1》开发项目时,每一个人都会从版本库的主分支下,分离一个子分支,在子分支下编写代码;
##2》代码编写完成后,将子分支合并到主分支即可;
核心原理
- 当使用 git commit 进行提交操作时,Git 先计算每一个子目录的校验和
- 然后在 Git 仓库中,将这些校验和保存为树对象
- 随后,Git 便会创建一个提交对象,它除了包含上面提到的那些信息外,还包含指向这个树对象(项目根目录)的指针
- 如此一来,Git 就可以在需要的时候,重现此次保存的快照
#1》计算要提交的每个文件的校验和(md5值),统一保存在对象变量tree中;
#2》commit 提交时,提交的是对象变量tree;
#3》对象变量tree中的每个md5值,都有对应文件;
- 做完修改后再次提交,那么这次产生的提交对象会包含一个指向上次提交对象(父对象)的指针。
#第一次提交:指针指向98ca9;
#第二次提交:指针指向34ac2,但提交对象中包含98ca9【parent】;
#第三次提交:指针指向f30ab,但提交对象中包含34ac22【parent】;
- Git 的分支,其实本质上仅仅是指向提交对象的可变指针
- Git 的默认分支名字是 master
- 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支
- 它会在每次的提交操作中自动向前移动
- master 并不是一个特殊分支,与其他分支没有区别
- Git 有一个名为 HEAD 的特殊指针,指向当前所在分支
master始终会指向最新的提交,HEAD指针指向当前所在的分支
创建分支:创建分支只是为你创建了一个可以移动的新的指针
[root@kube-node1 myweb]# git branch #查看所有的分支,'*'为当前所处的分支
[root@kube-node1 myweb]# git branch testing #创建新的分支testing,并不会切换分支
[root@kube-node1 myweb]# git checkout testing #切换到新的分支testing下
在新的分支testing下,产生文件并提交
[root@kube-node1 myweb]# cp /etc/hosts . #拷贝文件到当前目录下
[root@kube-node1 myweb]# git add . #新增或修改的所有文件,提交到暂存区
[root@kube-node1 myweb]# git commit -m 'add hosts' #提交到版本库
[root@kube-node1 myweb]# ls #查看当前目录下的文件hosts
在master主分支下,产生文件并提交
[root@kube-node1 myweb]# git checkout master
[root@kube-node1 myweb]# cp /etc/passwd .
[root@kube-node1 myweb]# git add .
[root@kube-node1 myweb]# git commit -m 'add passwd'
[root@kube-node1 myweb]# ls #查看主分支master下的文件,和其他分支不冲突
合并分支
[root@kube-node1 myweb]# git checkout master
[root@kube-node1 myweb]# git merge testing #将子分支testing合并到主分支下
删除分支
[root@kube-node1 myweb]# git branch -d testing #-d 删除分支testing
[root@kube-node1 myweb]# git branch #查看所有的分支, 分支删除成功