提交 cef5d950 编写于 作者: J jackfrued

更新了最后10天的文档

上级 8e719caa
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"\n",
"import pandas as pd"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"from pandas import Series,DataFrame"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"text/plain": [
"Math 120\n",
"Python 136\n",
"En 128\n",
"Chinese 99\n",
"dtype: int64"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 创建\n",
"# Series是一维的数据\n",
"s = Series(data = [120,136,128,99],index = ['Math','Python','En','Chinese'])\n",
"s"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(4,)"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.shape"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([120, 136, 128, 99], dtype=int64)"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v = s.values\n",
"v"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"numpy.ndarray"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(v)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"120.75"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.mean()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"136"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.max()"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"15.903353943953666"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.std()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": true
},
"outputs": [
{
"data": {
"text/plain": [
"Math 14400\n",
"Python 18496\n",
"En 16384\n",
"Chinese 9801\n",
"dtype: int64"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s.pow(2)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": true
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Python</th>\n",
" <th>En</th>\n",
" <th>Math</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>a</th>\n",
" <td>113</td>\n",
" <td>116</td>\n",
" <td>75</td>\n",
" </tr>\n",
" <tr>\n",
" <th>b</th>\n",
" <td>19</td>\n",
" <td>145</td>\n",
" <td>23</td>\n",
" </tr>\n",
" <tr>\n",
" <th>c</th>\n",
" <td>57</td>\n",
" <td>107</td>\n",
" <td>113</td>\n",
" </tr>\n",
" <tr>\n",
" <th>d</th>\n",
" <td>95</td>\n",
" <td>3</td>\n",
" <td>66</td>\n",
" </tr>\n",
" <tr>\n",
" <th>e</th>\n",
" <td>28</td>\n",
" <td>121</td>\n",
" <td>120</td>\n",
" </tr>\n",
" <tr>\n",
" <th>f</th>\n",
" <td>141</td>\n",
" <td>85</td>\n",
" <td>132</td>\n",
" </tr>\n",
" <tr>\n",
" <th>h</th>\n",
" <td>124</td>\n",
" <td>39</td>\n",
" <td>10</td>\n",
" </tr>\n",
" <tr>\n",
" <th>i</th>\n",
" <td>80</td>\n",
" <td>35</td>\n",
" <td>17</td>\n",
" </tr>\n",
" <tr>\n",
" <th>j</th>\n",
" <td>68</td>\n",
" <td>99</td>\n",
" <td>31</td>\n",
" </tr>\n",
" <tr>\n",
" <th>k</th>\n",
" <td>74</td>\n",
" <td>12</td>\n",
" <td>11</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Python En Math\n",
"a 113 116 75\n",
"b 19 145 23\n",
"c 57 107 113\n",
"d 95 3 66\n",
"e 28 121 120\n",
"f 141 85 132\n",
"h 124 39 10\n",
"i 80 35 17\n",
"j 68 99 31\n",
"k 74 12 11"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# DataFrame是二维的数据\n",
"# excel就非常相似\n",
"# 所有进行数据分析,数据挖掘的工具最基础的结果:行和列,行表示样本,列表示的是属性\n",
"df = DataFrame(data = np.random.randint(0,150,size = (10,3)),index = list('abcdefhijk'),columns=['Python','En','Math'])\n",
"df"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"(10, 3)"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.shape"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": true
},
"outputs": [
{
"data": {
"text/plain": [
"array([[113, 116, 75],\n",
" [ 19, 145, 23],\n",
" [ 57, 107, 113],\n",
" [ 95, 3, 66],\n",
" [ 28, 121, 120],\n",
" [141, 85, 132],\n",
" [124, 39, 10],\n",
" [ 80, 35, 17],\n",
" [ 68, 99, 31],\n",
" [ 74, 12, 11]])"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v = df.values\n",
"v"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"Python 79.9\n",
"En 76.2\n",
"Math 59.8\n",
"dtype: float64"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.mean()"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"Python 141\n",
"En 145\n",
"Math 132\n",
"dtype: int32"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.max()"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Python</th>\n",
" <th>En</th>\n",
" <th>Math</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>a</th>\n",
" <td>113</td>\n",
" <td>116</td>\n",
" <td>75</td>\n",
" </tr>\n",
" <tr>\n",
" <th>b</th>\n",
" <td>19</td>\n",
" <td>145</td>\n",
" <td>23</td>\n",
" </tr>\n",
" <tr>\n",
" <th>c</th>\n",
" <td>57</td>\n",
" <td>107</td>\n",
" <td>113</td>\n",
" </tr>\n",
" <tr>\n",
" <th>d</th>\n",
" <td>95</td>\n",
" <td>3</td>\n",
" <td>66</td>\n",
" </tr>\n",
" <tr>\n",
" <th>e</th>\n",
" <td>28</td>\n",
" <td>121</td>\n",
" <td>120</td>\n",
" </tr>\n",
" <tr>\n",
" <th>f</th>\n",
" <td>141</td>\n",
" <td>85</td>\n",
" <td>132</td>\n",
" </tr>\n",
" <tr>\n",
" <th>h</th>\n",
" <td>124</td>\n",
" <td>39</td>\n",
" <td>10</td>\n",
" </tr>\n",
" <tr>\n",
" <th>i</th>\n",
" <td>80</td>\n",
" <td>35</td>\n",
" <td>17</td>\n",
" </tr>\n",
" <tr>\n",
" <th>j</th>\n",
" <td>68</td>\n",
" <td>99</td>\n",
" <td>31</td>\n",
" </tr>\n",
" <tr>\n",
" <th>k</th>\n",
" <td>74</td>\n",
" <td>12</td>\n",
" <td>11</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Python En Math\n",
"a 113 116 75\n",
"b 19 145 23\n",
"c 57 107 113\n",
"d 95 3 66\n",
"e 28 121 120\n",
"f 141 85 132\n",
"h 124 39 10\n",
"i 80 35 17\n",
"j 68 99 31\n",
"k 74 12 11"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"Python 79.9\n",
"En 76.2\n",
"Math 59.8\n",
"dtype: float64"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.mean(axis = 0)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"a 101.333333\n",
"b 62.333333\n",
"c 92.333333\n",
"d 54.666667\n",
"e 89.666667\n",
"f 119.333333\n",
"h 57.666667\n",
"i 44.000000\n",
"j 66.000000\n",
"k 32.333333\n",
"dtype: float64"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.mean(axis = 1)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
......@@ -322,7 +322,7 @@
],
"source": [
"# DataFrame是二维的数据\n",
"# excel就非相似\n",
"# excel就非相似\n",
"# 所有进行数据分析,数据挖掘的工具最基础的结果:行和列,行表示样本,列表示的是属性\n",
"df = DataFrame(data = np.random.randint(0,150,size = (10,3)),index = list('abcdefhijk'),columns=['Python','En','Math'])\n",
"df"
......@@ -623,7 +623,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.5"
"version": "3.7.3"
}
},
"nbformat": 4,
......
## 团队项目开发准备
## 团队项目开发的问题和解决方案
我们经常听到个人开发和团队开发这两个词,所谓个人开发就是一个人把控产品的所有内容;而团队开发则是由多个人组成团队并完成产品的开发。要实施团队开发以下几点是必不可少的:
1. 必须对开发过程中的各种事件(例如:谁到什么时间完成了什么事情)进行管理和共享。
2. 各类工作成果以及新的知识技巧等必须在团队内部共享
1. 对开发过程中的各种事件(例如:谁到什么时间完成了什么事情)进行管理和共享。
2. 在团队内部共享各类工作成果以及新的知识技巧等
3. 管理工作成果的变更,既要防止成果被破坏,又要保证各个成员利用现有成果并行作业。
4. 能够证明团队开发出的软件在任何时候都是可以正常运行的。
5. 尽可能的使用自动化的工作流程,让团队成员能够正确的实施开发、测试和部署。
4. 证明团队开发出的软件在任何时候都是可以正常运行的。
5. 使用自动化的工作流程,让团队成员能够正确的实施开发、测试和部署。
### 团队项目开发常见问题
......@@ -62,7 +62,7 @@
### 版本控制
针对上面提到的一些问题,在团队开发的首要前提就是实施版本控制,对必要的信息进行管理,需要管理的内容包括:
针对上面提到的一系列问题,我们可以得出一个简单的结论,版本控制是实施团队开发的首要前提,必须通过版本控制对产品研发过程中产生的各种信息进行管理,这些内容包括:
1. 代码。
2. 需求和设计的相关文档。
......@@ -85,7 +85,41 @@ Git是诞生于2005年的一个开源分布式版本控制系统,最初是Linu
#### 安装Git
可以在[Git官方网站](http://git-scm.com/)找到适合自己系统的Git下载链接并进行安装,安装成功后可以在终端中键入下面的命令检查自己的Git版本。
可以在[Git官方网站](http://git-scm.com/)找到适合自己系统的Git下载链接并进行安装,macOS和Windows平台下安装Git都非常简单,Linux下如果要安装官方最新的版本,建议通过官方提供的Git源代码进行构建安装,步骤如下所示(以CentOS为例)。
下载Git源代码压缩文件。
```Shell
wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.23.0.tar.xz
```
解压缩和解归档。
```Shell
xz -d git-2.23.0.tar.xz
tar -xvf git-2.23.0.tar
```
安装底层依赖库。
```Shell
yum -y install libcurl-devel
```
安装前的配置。
```Shell
cd git-2.23.0
./configure --prefix=/usr/local
```
构建和安装。
```Shell
make && make install
```
安装成功后可以在终端中键入下面的命令检查自己的Git版本。
```Shell
git --version
......@@ -93,40 +127,60 @@ git --version
如果之前完全没有接触过Git,可以先阅读[《git - 简易指南》](http://www.bootcss.com/p/git-guide/)来对Git有一个大致的了解。
#### 本地实施版本控制
#### Git本地操作
可以使用下面的命令将目录创建为Git仓库。
可以使用下面的命令将一个文件夹变成Git仓库。
```Shell
git init
```
当你完成了上述操作后,本地目录就变成了下面的样子,左边是你正在操作的工作目录,而右边是你的本地仓库,中间是工作目录和本地仓库之间的一个暂存区(也称为缓存区)。
当你完成了上述操作后,本地目录就变成了下面的样子,下图左边是你的工作区(正在操作的工作目录),而右边是你的本地仓库,中间是工作区和本地仓库之间的暂存区(也称为缓存区)。
![](./res/git_repository.png)
通过`git add`可以将文件添加到暂存区。
> **提示**:用`ls -la`查看所有文件会发现在执行完上面的命令后,文件夹下多了一个名为`.git`的隐藏文件夹,这个文件夹就是Git版本仓库。
通过`git add`可以将指定的文件或所有文件添加到暂存区。
```Shell
git add <file> ...
git add <file>
git add .
```
可以用下面的方式将暂存区的指定文件恢复到工作区
这个时候使用下面的命令可以查看工作区、暂存区和本地仓库的状态
```Shell
git checkout -- <file>
git status
```
通过下面的命令可以将暂存区的内容纳入本地仓库
如果不希望将文件添加到暂存区,可以按照提示,使用下面的命令将文件从暂存区放回到工作区
```Shell
git commit -m '本次提交的说明'
git rm --cached <file>
```
可以使用下面的命令查看文件状态和进行版本比较
如果这个时候对工作区的文件又进行了修改使得工作区和暂存区的内容并不相同了,再次执行`git status`可以看到哪个或哪些文件被修改了,如果希望用暂存区的内容恢复工作区,可以使用下面的命令
```Shell
git status -s
git diff
git restore <file>
git restore .
```
> 提示:上面的命令目前仍然处于试验性阶段,在Git较早的版本中对应的命令是`git checkout -- <file>`。由于`git checkout`这个命令还可以用于切换分支,容易引起混淆,所以Git最新版本中将这个命令的两项功能分别赋予两个新的命令,一个就是上面的`git restore`,另一个是`git switch`。
如果第一次使用Git,需要配置用户名和邮箱,然后才能将代码提交到仓库。
```Shell
git config --global user.name "jackfrued"
git config --global user.email "jackfrued@126.com"
```
> **提示**:可以用`git config --list`来查看Git的配置信息。
通过下面的命令可以将暂存区的内容纳入本地仓库,
```Shell
git commit -m '本次提交的说明'
```
可以通过`git log`查看提交日志。
......@@ -143,70 +197,110 @@ git reset --hard <commit-id>
git reset --hard HEAD^
```
其他的一些命令可以参考阮一峰老师的[《常用Git命令清单》](http://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html)或者是码云上的[《Git大全》](https://gitee.com/all-about-git)
#### Git服务器概述
对于Git来说不像SVN那样一定需要一个中心服务器,刚才我们的操作都是在本地执行的,如果你想通过Git分享你的代码或者与其他人协作,那么就需要服务器的支持。Github为Git提供了远程仓库,它是一个基于Git的代码托管平台,企业用户(付费用户)可以创建仓库,普通用户只能创建公开仓库(代码是可以是他人可见的)。Github是在2008年4月创办的,它上面代码库惊人的增长速度已经证明了它是非常成功的,在2018年6月,微软以75亿美元的天价收购了Github。国内也有类似的代码托管平台,最有名的当属[码云](https://gitee.com/)[CODING](https://coding.net/),目前码云和CODING对注册用户都提供了受限的使用私有仓库的功能,同时还提供了对Pull Request的支持(后面会讲到),而且目前提供代码托管服务的平台都集成了“缺陷管理”、“WebHook”等一系列的功能,让我们能做的事情不仅仅是版本控制。当然,如果公司需要也可以搭建自己的Git服务器,具体的方式我们就不在这里进行介绍了,有兴趣的可以自行了解
Git不像SVN那样一定需要中央服务器才能工作,上面我们演示的版本控制操作都是在本地执行的,但是对于企业开发多人协作这样的环境就必须中央服务器的支持。通常,企业可以选择使用像Github这样的代码托管平台或自己搭建Git私服的方式来建立中央服务器。Github是一个基于Git的代码托管平台,企业用户(付费用户)可以创建私有仓库(仓库内容不对外公开),普通用户只能创建公开仓库(仓库内容对他人可见)。Github创办于2008年4月,目前是全世界最大的代码托管平台,它上面代码库惊人的增长速度也证明了它是非常成功的,在2018年6月被微软以75亿美元的天价收购,目前该平台已经向非企业用户开放了受限使用私有仓库的功能
![](./res/git_logo.png)
国内也有不少类似Github的代码托管平台,最有名的当属[码云](https://gitee.com/)[CODING](https://coding.net/),目前码云和CODING对注册用户都提供了受限的使用私有仓库的功能,支持**Pull Request**(本质是一种对话机制,可以在提交你的工作成果时让相关人员或团队注意到这件事情),同时还提供了对**缺陷管理****Web Hook**等功能支持,这些使得版本控制系统还具备了缺陷管理和持续集成的能力。当然,很多公司都不愿意将自己的商业代码托管于别人的平台,对于这样的公司可以使用[Gitlab](<https://about.gitlab.com/>)来搭建公司内部的Git私服,具体的做法在下一章为大家介绍。
我们可以在码云或者CODING上注册账号,也可以使用第三方登录(github账号、微信账号、新浪微博账号、CSDN账号等)的方式。登录成功后就可以创建项目,创建项目几乎是“傻瓜式”的,我们只说几个值得注意的地方。
![](./res/gitlab-about.png)
1. 添加项目成员。创建项目后,可以在项目的“设置”或“管理”中找到“成员管理”功能,这样就可以将其他开发者设置为项目团队的成员,项目成员通常分为“所有者”、“管理者”、“普通成员”和“受限成员”几种角色
这里我们直接以码云为例来说明Git服务器使用的一些注意事项。首先需要在码云上注册账号,当然也可以使用第三方登录(github账号、微信账号、新浪微博账号、CSDN账号等),登录成功后就可以创建项目,创建项目几乎是“傻瓜式”的,无需赘述,我们只对几个地方加以说明
2. 设置公钥实现免密操作。在项目的“设置”或“管理”中我们还可以找到“部署公钥管理”的选项,通过添加部署公钥,可以通过SSH(安全远程连接)的形式访问服务器而不用每次输入用户名和口令。可以使用`ssh-keygen`命令来创建密钥对。
1. 创建项目时不建议勾选如下图所示的这些选项,编程语言可以暂时不做选择,而`.gitignore`模板也可以稍后自己编写或者通过更专业的工具(如:<http://gitignore.io/>网站)自动生成。
![](./res/gitee-create-project.png)
2. 添加项目成员。创建项目后,可以在项目的“设置”或“管理”中找到“成员管理”功能,这样就可以将其他开发者设置为项目团队的成员,项目成员通常分为“所有者”、“管理者”、“普通成员”和“受限成员”几种角色。
![](./res/gitee-add-members.png)
3. 项目的分支。创建项目后,项目只有一个默认的**master**分支,应该将该分支设置为“保护分支”来避免项目管理者之外的成员修改该分支。
4. 设置公钥实现免密访问。在项目的“设置”或“管理”中我们还可以找到“部署公钥管理”的选项,通过添加部署公钥,可以通过SSH(安全远程连接)的方式访问服务器而不用每次输入用户名和口令。可以使用`ssh-keygen`命令来创建密钥对。
```Shell
ssh-keygen -t rsa -C "your_email@example.com"
ssh-keygen -t rsa -b 2048 -C "your_email@example.com"
```
#### 使用Git进行开发
> **说明**:上面命令生成的密钥对在`~/.ssh`目录下,公钥文件默认的名字为`id_rsa.pub`,可以通过`cat id_rsa.pub`来查看自己的公钥。Windows用户在安装Git之后,可以通过**Git Bash**来输入上面的命令。
克隆服务器上的代码到本地机器。
#### Git远程操作
```Shell
git clone <url>
```
在拥有了Git服务器之后,我们就可以通过Git的远程操作将自己的工作成果推到服务器上,也可以将他人的工作成果从服务器更新到本地,我们还是以刚才在码云上创建的名为`python`的仓库为例来说明如何进行远程操作。
在自己的分支上进行开发。
1. 指定远程主机(Git服务器)。
2. 将本地代码(工作成果)推送到远程主机。
3. 从远程主机取回代码。
```Shell
git branch <branch-name>
git checkout <branch-name>
```
#### Git分支操作
或者
1. 创建分支和切换分支。
```Shell
git checkout -b <branch-name>
```
```Shell
git branch <branch-name>
git switch <branch-name>
```
接下来可以先在本地实施版本控制(操作的方式与前面相同不再赘述),然后再将自己的分支Push到服务器。
```Shell
git push origin <branch-name>
```
```Shell
git switch -c <branch-name>
```
> **提示**:在之前的Git版本中,切换分支使用`git checkout <branch-name>`命令,也可以通过`git checkout -b <branch-name>`来创建并切换分支。`git switch`命令目前仍然处于试验性阶段,但很明显这个命令更加清晰的表达了它要做的事情。
2. 分支合并和变基。
3.
#### Git工作流程(分支管理策略)
既然Git是团队开发必备的工具,那么在团队协作时就必须有一个规范的工作流程,这样才能让团队高效的工作,让项目顺利的进展下去,否则工具再厉害但团队成员各自为战,冲突就会无处不在,协作更加无从谈起。我们仍然以刚才码云上创建的`python`项目为例,来说明Git的分支管理策略。
##### Github-flow
1. 克隆服务器上的代码到本地。
```Shell
git clone
```
2. 创建并切换到自己的分支。
```Shell
git switch -c
```
3. 在自己的分支上开发并在本地做版本控制。
4. 将自己的分支(工作成果)推到服务器。
```Shell
git push
```
5. 在线发起一次合并请求(通常称之为**Pull Request**,有的地方称为**Merge Request**),请求将自己的工作成果合并到master分支,合并之后可以删除该分支。
最后,当工作完成时,可以发起一个Pull Request,请求将代码合并到master分支。
![](./res/gitee-pull-request.png)
#### 分支策略的模式
上面这种分支管理策略就是被称为github-flow或PR的流程,它非常简单容易理解,只需要注意以下几点:
上面讲解的方式,其实是一种称为github-flow的分支策略模式,这种模式的操作步骤包括:
1. master的内容都是可以进行发布的内容(不能直接在master上进行修改)。
2. 开发时应该以master为基础建立新分支(日常开发任务在自己的分支上进行)。
3. 分支先在本地实施版本控制,然后以同名分支定期向服务器进行push操作。
4. 开发任务完成后向master发送合并请求。
5. 合并请求通过审查之后合并到master,并从master向正式环境发布。
1. master的内容都是可以进行发布的内容。
2. 开发时应该以master为基础建立新分支。
3. 分支先在本地实施版本控制,然后以同名分支定期向服务器进行Push。
4. 开发结束后向master发送Pull Request。
5. Pull Request通过代码审查之后合并到master,并从master向正式环境发布。
当然,github-flow的缺点也很明显,master分支默认就是当前的线上代码,但是有的时候工作成果合并到master分支,并不代表它就能立刻发布,这样就会导致线上版本落后于master分支。
在使用github-flow时的注意事项有以下三点:
##### Git-flow
1. master是用于发布的,不能直接在master上进行修改。
2. 开始日常开发工作时要首先建立分支。
3. 工作完成后向master发送Pull Request。
除了上述的github-flow分支管理策略外,还有一种名为git-flow的分支管理策略,它也是大多数公司愿意使用的一套流程。Git-flow借鉴了中央集权型版本控制系统的长处,为团队内部统一建立、合并和关闭分支的方法,如下图所示。
除了上述的github-flow工作方式外,还有一种名为git-flow的分支策略模式,它借鉴了中央集权型版本控制系统的长处,为团队内部统一管理建立分支的方法、合并操作和关闭分支的方法。在这种模式下,项目有两个长线分支,分别是master和develop,其他的都是临时的、短暂的辅助分支,包括feature(开发特定功能的分支,开发结束后合并到develop)、release(从develop分离出来的为发布做准备的分支,发布结束后合并到master和develop)和hotfix(产品发布后出现问题时紧急建立的分支,直接从master分离,问题修复后合并到master并打上标签,同时还要合并到develop来避免将来的版本遗漏了这个修复工作,如果此时有正在发布中的release分支,还要合并到release分支)。这套方式分支策略简单清晰且容易理解,但是在运用上会稍微有些复杂,需要一些脚本来辅助版本控制的实施。
![](./res/git-flow.png)
在这种模式下,项目有两个长线分支,分别是master和develop,其他都是临时的的辅助分支,包括feature(开发特定功能的分支,开发结束后合并到develop)、release(从develop分离出来的为发布做准备的分支,发布结束后合并到master和develop)和hotfix(产品发布后出现问题时紧急建立的分支,直接从master分离,问题修复后合并到master并打上标签,同时还要合并到develop来避免将来的版本遗漏了这个修复工作,如果此时有正在发布中的release分支,还要合并到release分支)。这套分支管理策略比较容易控制各个分支的状况,但是在运用上github-flow要复杂得多,所以实际使用的时候可以安装名为`gitflow`的命令行工具或者使用图形化的Git工具(如:SmartGit、SourceTree等),这样可以大幅度的简化版本控制操作,具体的可以参考[《git-flow 的工作流程》](<https://www.git-tower.com/learn/git/ebook/cn/command-line/advanced-topics/git-flow>)一文。
### 缺陷管理
......@@ -218,16 +312,52 @@ git push origin <branch-name>
4. 能够生成各类报表。
5. 能够关联到其他系统,具有可扩展性。
#### Redmine
Redmine是基于Ruby on Rails框架的开源缺陷管理系统,提供了问题管理、代码管理、Wiki等必要的功能,而且支持插件系统,扩展起来也非常容易。
![](./res/redmine_new_issue.png)
如果希望了解和使用Redmine,可以关注[Redmine中文网](http://www.redmine.org.cn/),上面提供了视频教程、经验分享以及其他的安装和使用上的指导。
如果希望了解和使用Redmine,可以关注[Redmine中文网](http://www.redmine.org.cn/),上面提供了视频教程、经验分享以及其他安装和使用上的指导。
#### 禅道
[禅道](<https://www.zentao.net/>)是国产的专业项目管理软件,它不仅仅是缺陷管理工具,它提供了完整软件生命周期管理功能,支持Scrum敏捷开发,能够实现需求管理、缺陷管理、任务管理等一系列的功能,而且拥有强大的扩展机制和丰富的功能插件。可以从禅道的官方网站提供的[下载链接](<https://www.zentao.net/download.html>)来下载禅道,推荐使用一键安装包。
下面仍然以CentOS Linux为例,讲解如何利用官方提供的一键安装包来安装禅道。
```Shell
cd /opt
wget http://dl.cnezsoft.com/zentao/pro8.5.2/ZenTaoPMS.pro8.5.2.zbox_64.tar.gz
gunzip ZenTaoPMS.pro8.5.2.zbox_64.tar.gz
tar -xvf ZenTaoPMS.pro8.5.2.zbox_64.tar
```
我们在`/opt`目录下(官方推荐使用这个目录)下载了禅道的归档压缩文件,并进行了解压缩和解归档的操作,完成上述步骤后,会看到一个名为`zbox`的文件夹。一键安装包中内置了Apache、MySQL、PHP等应用,也就是说这些都不需要单独安装部署了,接下来我们通过下面的命令来启动禅道。
```Shell
/opt/zbox/zbox -ap 8080 -mp 3307
/opt/zbox/zbox start
```
> 说明:上面使用`zbox`文件夹下的`zbox`命令,其中`-ap`是为了指定Apache服务器使用的端口,`-mp`是为了指定MySQL数据库使用的端口;`start`表示启动服务,`stop`可以用来停止服务。此外,需要打开防火墙8080端口以便访问禅道(Apache服务器)。
打开浏览器,输入服务器的IP地址就可以访问禅道,如果愿意,也可以通过DNS解析绑定一个域名来进行访问,禅道的首页如下图所示,默认的管理员是`admin`,口令是`123456`
![](./res/zentao-login.png)
第一次使用禅道时,建议通过点击用户名,然后通过“帮助”菜单的“新手教程”来迅速了解禅道。官方网站的文档链接中提供了[视频教程](<https://www.zentao.net/video/c1454.html>),初学者也可以通过视频教程来上手。
![](./res/zentao-index.png)
#### Gitlab
### 持续集成
为了快速的产生高品质的软件,在团队开发中,持续集成(CI)也是一个非常重要的基础。按照经典的软件过程模型(瀑布模型),集成的工作一般要等到所有的开发工作都结束后才能开始,但这个时候如果发现了问题,修复问题的代价是非常具体的。基本上,集成实施得越晚,代码量越大,解决问题就越困难。持续集成将版本控制、自动化构建、代码测试融入到一起,让这些工作变得自动化和可协作。由于其频繁重复整个开发流程(在指定时间内多次pull源代码并运行测试代码),所以能帮助开发者提早发现问题。
在所有的CI工具中,Jenkins和TravisCI是最具有代表性的
在所有的CI工具中,Jenkins和[TravisCI](<https://www.travis-ci.org/>)是最具有代表性的,前者是基于 Java的开源CI工具,后者是新晋的在线CI工具。我们可以借助Docker来安装Jenkins(下一章节讲解),安装后……。Jenkins不仅能在面板上轻松看出任务成功或失败,还可以借助通知功能将结果以邮件或RSS订阅的形式发给用户。与此同时,Jenkins也允许通过插件进行功能扩展,所需功能可以随用随添加,而且还支持主从式集群,能够轻松的进行水平扩展
![](./res/jenkins_new_project.png)Jenkins 是基 Java的开源CI工具,其安装和操作都很简单。另外,Jenkins不仅能在面板上轻松看出任务成功或失败,还可以借助通知功能将结果以邮件或RSS订阅的形式发给用户。与此同时,Jenkins也允许通过插件进行功能扩展,所需功能可以随用随添加,而且还支持主从式集群,能够轻松的进行水平扩展。
\ No newline at end of file
![](./res/jenkins_new_project.png)
\ No newline at end of file
## 使用Docker部署服务
## 使用Docker部署应用
### Docker简介
......@@ -112,7 +112,7 @@ docker rmi hello-world
>
> 国内用户可以通过更换Ubuntu软件下载源来提升下载速度,具体请参照清华大学开源软件镜像站上的[《Ubuntu镜像使用帮助》](<https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/>)。
安装Docker后,由于直接访问[dockerhub](https://hub.docker.com/)下载镜像会非常缓慢,建议将服务器更换为国内镜像,可以通过修改 `/etc/docker/daemon.js` 文件来做到。
安装Docker后,由于直接访问[dockerhub](https://hub.docker.com/)下载镜像会非常缓慢,建议将服务器更换为国内镜像,可以通过修改 `/etc/docker/daemon.js` 文件来做到。一般的云服务器会有自己专属的镜像,就不需要手动修改了。
```JavaScript
{
......@@ -125,9 +125,11 @@ docker rmi hello-world
### 使用Docker
#### 安装Nginx
想要玩转Docker,最简单的办法就是马上用Docker创建一些自己学习和工作中需要用到的容器,接下来我们就带着大家一起来创建这些容器。
下面我们就基于Docker来创建一台HTTP服务器,我们选择用Nginx来搭建该服务,因为Nginx是高性能的Web服务器,同时也是做反向代理服务器的上佳选择。要做到这件事情,只需要使用下面的命令在Docker中创建一个容器即可。
#### 运行Nginx
Nginx是高性能的Web服务器,同时也是做反向代理服务器的上佳选择。使用Docker可以非常简单的创建一个运行Nginx的容器,命令如下所示。
```Shell
docker container run -d -p 80:80 --rm --name mynginx nginx
......@@ -191,7 +193,7 @@ docker rm mynginx
docker rm -f mynginx
```
#### 安装MySQL
#### 运行MySQL
我们再来尝试用Docker安装一台MySQL服务器,首先可以先检查一下有没有MySQL的镜像文件。
......@@ -231,7 +233,9 @@ docker.io/mysql 5.7 f6509bac4980 3 weeks ago
docker run -d -p 3306:3306 --name mysql57 -v $PWD/mysql/conf:/etc/mysql/mysql.cnf.d -v $PWD/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
```
注意,上面创建容器时我们又一次使用了数据卷操作,那是因为通常容器是随时创建随时删除的,而数据库中的数据却是需要保留下来的,所以上面的两个数据卷操作一个是映射了MySQL配置文件所在的文件夹,一个是映射了MySQL数据所在的文件夹,这里的数据卷操作非常重要。我们可以将MySQL的配置文件放在`$PWD/mysql/conf`目录下,配置文件的具体内容如下所示:
> **注意**:上面创建容器时我们又一次使用了数据卷操作,那是因为通常容器是随时创建随时删除的,而数据库中的数据却是需要保留下来的。
上面的两个数据卷操作一个是映射了MySQL配置文件所在的文件夹,一个是映射了MySQL数据所在的文件夹,这两个数据卷操作非常重要。我们可以将MySQL的配置文件放在`$PWD/mysql/conf`目录下,配置文件的具体内容如下所示:
```INI
[mysqld]
......@@ -289,7 +293,7 @@ select user, host, plugin, authentication_string from user where user='root';
在完成上面的步骤后,现在即便不更新客户端工具也可以连接MySQL 8.x了。
#### 安装Redis
#### 运行Redis
接下来我们试一试运行多个容器并让多个容器之间通过网络通信。我们创建4个Redis容器来实现一主三从的主从复制结构。
......@@ -329,9 +333,19 @@ repl_backlog_first_byte_offset:1
repl_backlog_histlen:1988
```
#### 运行Gitlab
#### 运行Jenkins
### 构建镜像
Docker镜像是由文件系统叠加而成的,系统的最底层是bootfs,相当于就是Linux内核的引导文件系统;接下来第二层是rootfs,这一层可以是一种或多种操作系统(如Debian或Ubuntu文件系统),Docker中的rootfs是只读状态的;Docker利用联合挂载技术将各层文件系统叠加到一起,最终的文件系统会包含有底层的文件和目录,这样的文件系统就是一个镜像,如下图所示。
通过上面的讲解,我们已经掌握了如何通过官方提供的镜像来创建容器。当然如果愿意,我们也可以用配置好的容器来生成镜像。简而言之,Docker镜像是由文件系统叠加而成的,系统的最底层是bootfs,相当于就是Linux内核的引导文件系统;接下来第二层是rootfs,这一层可以是一种或多种操作系统(如Debian或Ubuntu文件系统),Docker中的rootfs是只读状态的;Docker利用联合挂载技术将各层文件系统叠加到一起,最终的文件系统会包含有底层的文件和目录,这样的文件系统就是一个镜像,如下图所示。
![](./res/docker-image.png)
之前我们讲过了如何查找、列出镜像和拉取(下载)镜像,接下来看看构建镜像的两种方式:
......@@ -391,11 +405,9 @@ jackfrued/mywebserver latest 795b294d265a 14 seconds ago 189 MB
Dockerfile使用DSL(Domain Specific Language)来构建一个Docker镜像,只要编辑好了Dockerfile文件,就可以使用`docker build`命令来构建一个新的镜像。
我们先创建一个新的文件夹并在文件夹下创建名为Dockerfile的文件。
我们先创建一个文件夹并在文件夹下创建名为Dockerfile的文件。
```Shell
mkdir test
cd test
touch Dockerfile
```
......@@ -422,6 +434,8 @@ EXPOSE 80
docker build -t="jackfrued/webserver" .
```
> 提示:上面的命令最后面的`.` 千万不要漏掉了哦,它表示从当前路径下寻找Dockerfile。
通过下面的命令可以查看创建好的镜像。
```Shell
......@@ -795,5 +809,5 @@ docker push jackfrued/webserver
... ...
```
### 集群管理
## 网络API接口设计
手机App以及使用了Ajax技术或做了前后端分离的页面都需要通过网络API(Application Programming Interface)和后台进行交互,所谓API,指的应用程序的编程接口;而网络API通畅指的是基于HTTP或HTTPS协议的一个URL(统一资源定位符),通过这个URL我们可以让服务器对某个资源进行操作并返回操作的结果。基于HTTP(S)协议最大的好处就在于访问起来非常的简单方便,而且没有编程语言和应用环境上的差别。
目前许多的Web应用和移动应用都使用了前后端分离的开发模式,前后端分离简单的说就是前端或移动端通过网络API接口和后台进行交互。API是应用程序的编程接口的缩写;网络API通常指的是基于一个URL(统一资源定位符)可以访问到的资源,也就是说通过这个URL我们可以让服务器对某个资源进行操作并返回操作的结果,复杂的业务逻辑被隐藏在简单的API接口中。URL的通用格式如下所示:
```
协议://用户名:口令@主机:端口/路径1/.../路径N/资源名
```
> 说明:URL中的用户名(有可能不需要提供用户名)、口令(有可能不需要提供口令)、端口(有可能使用默认端口)、路径(资源有可能直接位于根路径`/`下)并不是必需的部分,可以根据需要进行设置。
网络API通常基于HTTP或HTTPS进行访问,基于HTTP/HTTPS最大的好处就在于访问起来非常的简单方便,而且可以跨语言、跨应用进行访问和互操作。
### 设计原则
......@@ -20,9 +28,9 @@
| comments/destroy | 删除一条评论 |
| comments/reply | 回复一条评论 |
注意:上面的API接口并不是REST风格的,关于REST的知识,可以阅读阮一峰老师的[《理解RESTful架构》](http://www.ruanyifeng.com/blog/2011/09/restful.html)以及[《RESTful API设计指南》](http://www.ruanyifeng.com/blog/2014/05/restful_api.html)
需要说明的是,上面的API接口并不是REST风格的。REST是一种网络应用架构风格,被认为最适合分布式的网络应用。关于REST的知识,可以阅读阮一峰老师的[《理解RESTful架构》](http://www.ruanyifeng.com/blog/2011/09/restful.html)以及[《RESTful API设计指南》](http://www.ruanyifeng.com/blog/2014/05/restful_api.html),当然这两篇文章大家也要批判的阅读,因为上面阐述的观点并不完全正确,有些内容甚至是自相矛盾的
API接口返回的数据通常都是JSON或XML格式,我们这里不讨论后者。对于JSON格式的数据,我们需要做到不要返回null这的值,因为这样的值一旦处置失当,会给移动端的开发带来麻烦(移动端可能使用强类型语言)。要解决这个问题可以从源头入手,在设计数据库的时候,尽量给每个字段都加上“not null”约束或者设置合理的默认值约束。
API接口返回的数据通常都是**JSON****XML**格式,我们这里不会讲述XML的知识,因为这种格式几乎已经被淘汰掉了。对于JSON格式的数据,我们需要做到不要返回null这的值,因为这样的值一旦处置失当,会给前端和移动端开发带来不必要的麻烦(因为开发者有可能会使用强类型语言)。要解决这个问题可以从源头入手,在设计数据库的时候,尽量给每个字段都加上“not null”约束或者设置合理的默认值约束。
#### 其他问题
......
......@@ -2,9 +2,9 @@
> 作者:骆昊
>
> 最近有很多想学习Python的小伙伴陆陆续续加入我们的交流群,目前我们的交流群人数已经超过一万人,光靠我自己已经无法及时处理小伙伴们的入群申请,更无法及时为大家解答问题。目前我的想法是分技术方向建立讨论群并安排专门的人来管理这些群,群管理者应该具备专业的知识并有相对充裕的时间,可以解答小伙伴们提出的问题。当然,我会向这些管理者支付报酬,如果有兴趣成为管理者的可以跟我私聊。但愿通过这种方式,我们的群能汇聚更多优秀的Python开发者,一方面打造一个优质的沟通和交流的平台,另一方面让新入行的开发者获得问道的途径并藉此迅速成长。我会继续努力做好线上公开课以及线下技术交流活动,也希望各位小伙伴一如既往的支持我们。创作不易,感谢大家的打赏支持,这些钱不会用于购买咖啡而是通过腾讯公益平台捐赠给需要帮助的人([点击](./更新日志.md)了解捐赠情况)。感谢**北京千锋互联科技有限公司**对[公开课](https://ke.qq.com/course/406954)提供的支持。
> 最近有很多想学习Python的小伙伴陆陆续续加入我们的交流群,目前我们的交流群人数已经超过一万人。我们的目标是打造一个优质的Python交流社区,一方面为想学习Python的初学者扫平入门过程中的重重障碍;另一方为新入行的开发者提供问道的途径,帮助他们迅速成长为优秀的职业人;此外,有经验的开发者可以利用这个平台把自己的工作经验无偿分享或有偿提供出来,让大家都能够得到职业技能以及综合素质的全面提升。之前的公开课和线下技术交流活动因为工作的关系荒废了一段时间了,但是各位小伙伴仍然活跃在交流群并一如既往的支持我们,在此向大家表示感谢。近期开始持续更新前15天和最后10天的内容,前15天是写给初学者的,我希望把上手的难度进一步降低,例子程序更加简单清晰;最后10天是Python项目实战和面试相关的东西,我希望内容更详实和完整,尤其是第100天的面试题部分;创作不易,感谢大家的打赏支持,这些钱不会用于购买咖啡而是通过腾讯公益平台捐赠给需要帮助的人([点击](./更新日志.md)了解捐赠情况)。感谢**北京千锋互联科技有限公司**对[公开课](https://ke.qq.com/course/406954)提供的支持。
![](./res/python_qq_group.jpg)
![](./res/python-qq-group.png)
### Python应用领域和就业形势分析
......@@ -456,7 +456,7 @@
### Day91~100 - [团队项目开发](./Day91-100)
#### 第91天:[团队项目开发准备](./Day91-100/91.团队项目开发准备.md)
#### 第91天:[团队项目开发的问题和解决方案](./Day91-100/91.团队项目开发的问题和解决方案.md)
1. 软件过程模型
- 经典过程模型(瀑布模型)
......@@ -568,11 +568,19 @@
python manage.py inspectdb > app/models.py
```
#### 第92天:[使用Docker部署应用](./Day91-100/92.使用Docker部署应用.md)
#### 第92天:[Docker的使用](./Day91-100/92.Docker在项目中的应用.md)
1. Docker简介
2. 安装Docker
3. 使用Docker创建容器(Nginx、MySQL、Redis、Gitlab、Jenkins)
4. 构建Docker镜像(Dockerfile的编写和相关指令)
5. 容器编排(Docker-compose)
6. 集群管理
#### 第93天:[MySQL性能优化](./Day91-100/93.MySQL性能优化.md)
1.
#### 第94天:[网络API接口设计](./Day91-100/94.网络API接口设计.md)
#### 第95天:[使用Django开发商业项目](./Day91-100/95.使用Django开发商业项 目.md)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册