Install-Python3.6-on-CentOS7

拖了很久没有更新,抱歉啦~ 今天受邀写篇如何在 CentOS 7 上配置 Python 3 环境的文章。往常我都选择直接把我早年写的一篇文章源码编译MongoDB丢过去,让他们看其中的源码编译 Python 那一节,不过那节写的其实不太详细,而且最近被很多人催,所以还是单独写一篇好了。

当前最新的 CentOS 7.3 默认安装的是 Python 2 ,并且默认的官方 yum 源中不提供 Python 3 的安装包。有些用户想要升级使用 Python 3 但实际可能有各种各样的问题,导致出错,反观一下激进的 Fedora 社区,在23的时候,就将默认的版本修改成了 Python3 (如果我没记错的话)。

先说下我所使用的系统环境, 一个新创建的 Docker 容器。 使用 cat /etc/redhat-release 可以看到运行的是 CentOS 7.3 版本。

systeminfo

在纯净的 CentOS 系统上安装 Python 环境主要有两种办法。 一种是通过源码编译安装,另外一种就是安装已经打好的 RPM 包。依照个人习惯,我们先来看一下如何通过源码编译的方式安装 Python 3.6 并且配置虚拟环境。

使用源码进行编译安装

基础环境

  • 先安装安装几个必须的包,以方便后续的操作
1
2
3
➜ yum install wget gcc make
➜ # wget 用于下载源码包
➜ # gcc 和 make 用于编译

install_gcc_wget

1
➜ wget https://www.python.org/ftp/python/3.6.1/Python-3.6.1.tar.xz
  • 解包,解压缩
1
2
➜ xz -d Python-3.6.1.tar.xz
➜ tar -xvf Python-3.6.1.tar

decompress_archives

  • 编译
1
2
3
➜ cd Python-3.6.1
➜ ./configure --prefix=/usr/local/python3.6 --enable-optimizations

先解释下上面的参数,--prefix 是预期安装目录,--enable-optimizations 是优化选项(LTO,PGO 等)加上这个 flag 编译后,性能有 10% 左右的优化(如果没记错的话),但是这会明显的增加编译时间。不过关于 LTO 和 PGO 其实不在今天文章的讨论范围内,建议感兴趣的可以看看 GCC 中 LTO 的具体实现。我应该不太可能去写相关的文章 哈哈哈 毕竟写起来就会停不下来。

接下来

1
2
➜ make
➜ make install

make_error

如图,会看到出错了,提示 zlib not available 所以,我们需要装一下依赖

1
➜ yum install zlib-devel

那为什么需要这个依赖包呢, 其实是因为 Python 有个很重要的内建模块 zipimport 用于从 Zip 压缩包中导入模块。 而如果没有 zlib 的包,那么就无法进行解压缩了,也自然该模块就不能使用了。

当我们的依赖安装好之后,重新执行上面的编译安装的步骤,发现执行成功。

1
2
➜ /usr/local/python3.6/bin/python3 --version
Python 3.6.1

install_success

此刻,我们的 Python 3 也就安装成功了。

  • 检查

编译安装完还远远不够,我们来做些检查。

当我们运行 Python 终端,输入 import bz2 的时候,会发现没有这个模块。如果你对这个模块不熟悉,那也没关系。我们输入 import sqlite3熟悉 Python 的同学应该对 sqlite3 不会太陌生,但如果你还是不熟悉的话,那你按方向键试试看。有没有发现,输出变成了^[[D^[[A 类似这样的内容?

arrow_keys_problem

熟悉 Python 源码的同学,肯定知道我要说什么了。但是假如你不熟悉,没关系,我来告诉你。正常来讲,在终端下我们预期当输入上方向键,会显示上一条命令,输入左方向键,可以将光标移动到左侧。但现实和我们的预期不同,什么原因?

这里涉及到了一点点关于输入设备的历史原因,简单来说就是需要有个模块来对用户的输入进行转义。回到本文的重点,就是我们编译安装的时候缺少了 readline 这个模块。既然已经发现了问题,那解决的办法其实很简单

1
➜ yum install readline-devel

安装完成后,重复上面的步骤,编译&&安装即可。

  • 再检查

前面只是解决了方向键输入的问题,但是我提到的那两个模块还是 import 不进来,那我们仔细的看看我们的编译过程的输出。其中有这样的一段(依据系统环境的不同,输出可能也是不一致的)

1
2
3
4
5
6
7
8
Python build finished successfully!
The necessary bits to build these optional modules were not found:
_curses bz2 _dbm
_gdbm _lzma _sqlite3
_tkinter readline
To find the necessary bits, look in setup.py in detect_modules() for the module's name.

some_optional_modules_were_not_found

按照上面的提示,很明显,我们缺少了一些(可选的)模块,这些模块假如你觉得自己不会用到,那也可以不理会它。这些模块,我用到的会多一些,甚至是那个一般人都不会碰的 TK 模块 哈哈哈。解决方式就只是装一下对应的模块即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
➜ # 解决 import bz2 报错
➜ yum install bzip2-devel
➜ # 解决 import curses 报错
➜ yum install ncurses-devel
➜ # 解决 import sqlite3 报错
➜ yum install sqlite-devel
➜ # 解决 _dbm _gdbm 缺失提醒
➜ yum install gdbm-devel
➜ # 解决 _lzma 缺失提醒
➜ yum install xz-devel
➜ # 解决 _tkinter 缺失提醒
➜ yum install tk-devel
➜ # 解决 readline 缺失提醒及方向键行为非预期的问题
➜ yum install readline-devel

当这些模块都装完,重新编译会发现提醒已经消失,安装即可。

all_modules_were_found

import_successful

使用 rpm 包进行安装

先来介绍一下 IUS 这个社区,名字的全写是【Inline with Upstream Stable】取首字母,它主要是一个提供新版本RPM包的社区。具体使用可以查看官方文档 简单说来就只要按下面的命令操作即可。

1
➜ yum -y install https://centos7.iuscommunity.org/ius-release.rpm

yum_install_ius

添加 IUS 之后,先创建缓存元数据,再进行安装即可

1
2
3
4
➜ yum makecache
➜ yum install python36u
➜ yum -y install python36u-pip
➜ yum -y install python36u-devel

yum_install_python36u

完成后直接终端输入 python3 即可。

环境配置

上面只是写了 Python 的安装,如果是使用 RPM 的方式安装的话,那直接是可用的。但如果是源码编译的,总不至于每次都输入一大串路径吧。所以解决方法很简单,加个链接即可。

1
➜ ln -s /usr/local/python3.6/bin/python3 /usr/bin/python3

ln

另外,当系统中存在多个 Python 版本的时候,尽量去避免环境污染。我个人比较推荐使用 virtualenv 创建独立的虚拟环境,我日常中也是这样用的。不过,当我们安装完 Python 3.6 后,可以直接执行下面的命令进行虚拟环境的创建。

1
2
3
4
➜ python3 -m venv py3
➜ source py3/bin/activate
(py3) ➜ python -V
Python 3.6.1

总结

CentOS 7 上安装Python 3.6 主要有两种方式,源码编译和安装 RPM 包。

对于想快速使用源码配置环境但并不想关心具体原因的读者,可以直接使用我GitHub上提供的这个脚本进行安装 https://raw.githubusercontent.com/tao12345666333/dotfiles/master/env/install_Python36_on_CentOS7.sh

另外Python 3.6 可直接使用 python3 -m venv venv_name 创建虚拟环境。


可以通过下面二维码订阅我的文章公众号【MoeLove】

TheMoeLove

理解 Redis 的 RESP 协议

简介

Redis 的客户端和服务端之间采取了一种独立名为 RESP(REdis Serialization Protocol) 的协议,作者主要考虑了以下几个点:

  • 容易实现
  • 解析快
  • 人类可读

注意:RESP 虽然是为 Redis 设计的,但是同样也可以用于其他 C/S 的软件。

数据类型及示例

RESP 主要可以序列化以下几种类型:整数,单行回复(简单字符串),数组,错误信息,多行字符串。Redis 客户端向服务端发送的是一组由执行的命令组成的字符串数组,服务端根据不同的命令回复不同类型的数据,但协议的每部分都是以 “\r\n” (CRLF) 结尾的。另外 RESP 是二进制安全的,不需要处理从一个进程到另一个进程的传输,因为它使用了前缀长度进行传输。

在 RESP 中, 一些数据的类型通过它的第一个字节进行判断:

  • 单行回复:回复的第一个字节是 “+”
  • 错误信息:回复的第一个字节是 “-“
  • 整形数字:回复的第一个字节是 “:”
  • 多行字符串:回复的第一个字节是 “\$”
  • 数组:回复的第一个字节是 “*”

单行回复

以 “+” 开头,以 “\r\n” 结尾的字符串形式。e.g.

1
+OK\r\n

响应的客户端库,应该返回除 “+” 和 CRLF 以外的内容,例如上面的内容,则返回 “OK”. e.g.

1
2
3
4
127.0.0.1:6379> set name TaoBeier
+OK\r\n # 服务端实际返回
---
OK # redis-cli 客户端显示

错误信息

错误信息和单行回复很像,不过是把 “+” 替换成了 “-“。而这两者之间真正的区别是,错误信息会被客户端视为异常,并且组成错误类型的是错误消息本身。e.g.

1
-Error message\r\n

错误信息只在有错误发生的时候才会发送,比如数据类型错误,语法错误,或者命令不存在之类的。而当接收到错误信息的时候,客户端库应该抛出一个异常。e.g.

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> TaoBeier
-ERR unknown command 'TaoBeier'\r\n # 服务端实际返回, 下同
---
(error) ERR unknown command 'TaoBeier' # redis-cli 客户端显示, 下同
127.0.0.1:6379> set name TaoBeier moelove
-ERR syntax error\r\n
---
(error) ERR syntax error

整数

这种类型只是只是使用以 “:” 作为前缀,以CRLF作为结尾的字符串来表示整数。e.g. “:666\r\n” 或者 “:999\r\n” 这种的都是整数回复。很多命令都会返回整数回复,例如 INCR LLEN LPUSH 之类的命令。但是多数情况下,返回的整数回复并没有过多实际含义,例如 LPUSH 就只是为了表示插入了几个值,但也有例如 EXISTS 命令是当结果为 true 的时候返回 1,false 返回 0 . e.g.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
127.0.0.1:6379> LPUSH info TaoBeier MoeLove
:2\r\n # 服务端实际返回, 下同
---
(integer) 2 # redis-cli 客户端显示, 下同
127.0.0.1:6379> LLEN info
:2\r\n
---
(integer) 2
127.0.0.1:6379> EXISTS info
:1\r\n
---
(integer) 1
127.0.0.1:6379> DEL info
:1\r\n
---
(integer) 1
127.0.0.1:6379> EXISTS info
:0\r\n
---
(integer) 0

多行字符串

多行字符串被服务端用来返回长度最大为 512MB 的单个二进制安全的字符串。以 “\$” 开头, 后跟实际要发送的字节数,随后是 CRLF,然后是实际的字符串数据,最后以 CRLF 结束。所以,例如我们要发送一个 “moelove.info” 的字符串,那它实际就被编码为 “\$12\r\nmoelove.info\r\n”。而如果一个要发送一个空字符串,则会编码为 “\$0\r\n\r\n” 。某些情况下,当要表示不存在的值时候,则以 “\$-1\r\n” 返回,这被叫做空多行字符串,当客户端库接收到这个响应的时候,同样应该返回一个空值(例如 nil)而不是一个空字符串。e.g.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
127.0.0.1:6379> set site moelove.info
+OK\r\n # 服务端实际返回, 下同
---
OK # redis-cli 客户端显示, 下同
127.0.0.1:6379> get site
$12\r\nmoelove.info\r\n
---
"moelove.info"
127.0.0.1:6379> del site
:1\r\n
---
(integer) 1
127.0.0.1:6379> get site
$-1\r\n
---
(nil)
127.0.0.1:6379> set site ''
+OK\r\n
---
OK
127.0.0.1:6379> get site
$0\r\n\r\n
---
""

数组

数组类型可用于客户端向服务端发送命令,同样的当某些命令将元素结合返回给客户端的时候,也是使用数组类型作为回复类型的。它以 “*” 开头,后面跟着返回元素的个数,随后是 CRLF, 再然后就是数组中各元素自己的类型了。最典型的是 LRRANGE 命令,返回一个列表中的元素。e.g.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
127.0.0.1:6379> LPUSH info TaoBeier moelove.info
:2\r\n # 服务端实际返回, 下同
---
(integer) 2 # redis-cli 客户端显示, 下同
127.0.0.1:6379> LRANGE info 0 -1
*2\r\n$12\r\nmoelove.info\r\n$8\r\nTaoBeier\r\n
---
1) "moelove.info"
2) "TaoBeier"
127.0.0.1:6379> LPOP info
$12\r\nmoelove.info\r\n
---
"moelove.info"
127.0.0.1:6379> LPOP info
$8\r\nTaoBeier\r\n
---
"TaoBeier"
127.0.0.1:6379> LRANGE info 0 -1
*0\r\n
---
(empty list or set)

总结

RESP 协议还是相对易于理解的,另外理解了协议也方便对 Redis 一些问题的定位及客户端的实现。

参考:


可以通过下面二维码订阅我的文章公众号【MoeLove】

2016 小回顾

github-2016.png

时间很快, 已经走到了 2016 的末尾, 惯例的做个小回顾。(注:这篇起笔的时间是圣诞节TAT)

年初定的目标除了没有能合理安排追番时间, 其他的都基本完成了!(话说今年追番的时间简直少的可怜QAQ)

2016 年发生了太多的事情,要回顾的事情很多,索性就不写那么多了, 只按时间序稍微列几件有趣的事情。

  • 单表亿级数据量的 MongoDB 做在线实时的数据拆分
  • 在之前做的一些应用性能分析的方案上做了一些额外的设计和开发(明年修改下开源出来)
  • PyCon China 2016
  • 一些预期的计划顺利推进、落地,产出了一些系统
  • 看了很多源码,折腾了很多东西,如果以后有空就写点东西出来(我又在给自己挖坑了)
  • 认识了很多有趣的小伙伴~

全年的状态基本和上面的截图是一致的, 全年都在 coding (截图仅限 GitHub上的记录)倒也比较开心, 另外就是现在看到自己项目的 star/fork 数,文章的阅读/收藏/转发数之类的,也已经不像以前看到 star 数刚上百时候会有那种喜悦了,大概这也是另一种成熟? 哈哈哈

另外写一下今年对我比较重要的几个数字:

  • 1354
  • 376
  • 105

对这些数字的解释, 放在以后吧 :-)

2017 年,希望想做的事情都能基本完成,挖的坑慢慢填。 感谢一路上陪我走过的各位!


可以通过下面二维码订阅我的文章公众号【MoeLove】

MoeLove

关于 webpack 你可能忽略的细节(附源码分析)

注:本篇不是入门教程,入门请直接查看官方文档。本篇的主要目标是通过实际问题来介绍 webpack 中容易被人忽略的细节, 以及源码分析(以最新发布的 release 版本1.14.0的源码为例), 并且提供几种解决方案。

webpack from the official website

随着前端技术的火热发展,工程化,模块化和组件化的思想已逐步成为主流,与之相应的,就需要有一整套工具流可以支撑起它。

现在比较热门的前端资源模块化管理和打包工具应该非 Webpack 莫属了。

Webpack 是什么

它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分隔,等到实际需要的时候再异步加载。通过 loader 的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块、 AMD 模块、 ES6 模块、CSS、图片、 JSON、Coffeescript、 LESS 等。
–引自 Webpack 中文指南

使用举例

我们来看一下官方文档中的最小用例,新建并写入以下内容到这两个文件:

cats.js

1
2
var cats = ['dave', 'henry', 'martha'];
module.exports = cats;

app.js (Entry Point)

1
2
cats = require('./cats.js');
console.log(cats);

这个时候,就可以使用 webpack 进行打包了:

1
webpack ./app.js app.bundle.js

我们来看一下发生了什么, 目录下生成了一个打包后的文件 app.bundle.js ,这就是最基础的打包过程。

提出问题

如何判断打包是否成功?

通用方案

下面是我们常用的两种判断任务是否执行成功的方案

通过 return code

通过命令执行后的 return code 来判断(在 shell 中使用 $? 获得)。 并且通常情况下 0 是执行成功, 非 0 是未成功。 我们以上面的例子来测试一下:

webpack-demo.png

可以看到 $? 的值为 0 , 且打包后的文件运行正常。

那么我们来修改一下 app.js 文件的内容, 将 require 引入的模块路径故意写错,来测试一下:

webpack-error.png

注意:箭头处 $? 的值仍然为 0, 且生成的打包后的文件运行出错。

这就说明,根据 return code 的值判断任务是否执行成功, 不可行!

通过标准错误输出

我们也会通过标准错误输出stderr)来判断一个任务执行过程中是否有错误输出。还是使用上面的例子做示范:

webpack-stderr.png

根据这个例子,可以看到 webpack 并没有标准错误输出!所以这个方法也不可行。

探究原因及源码分析

这里以最新发布的 release 版本 1.14.0 的源码作为分析。 在 lib/Compilation.js 中我们可以看到这样一段代码:

1
2
3
4
5
6
7
8
9
10
11
var errorAndCallback = function errorAndCallback(err) {
err.dependencies = dependencies;
err.origin = module;
module.dependenciesErrors.push(err);
_this.errors.push(err);
if(bail) {
callback(err);
} else {
callback();
}
};

在源码中可以看到这个函数其实被调用的还比较多, 例如:在模块为可选的时候, 会判断只是抛出警告还是处理错误, 而上面这段代码自然也不必多数, 关键点在于 bail 的值, 而我们继续找, 可以看到在 bin/config-optimist.js 中有对 bail 参数的解析, 这是一个布尔值。而因为没有太多描述, 所以这个参数就经常容易被忽略。

解决方案

1. 加 bail 参数

基于上面简要的分析, 我们来尝试下 bail 参数的作用。 仍然使用上面的例子:

我们使用 webpack --bail true app.js app.bundle.js 进行测试

webpack-bail.png

可以看到, 使用 bail 参数并传递 true 进去, 在遇到错误的时候,打包过程将会退出, return code1 且把错误信息打印到 stderr .

2. 使用 webpack-fail-plugin

webpack-fail-plugin 是专为解决这个问题而生的,它会在错误发生的时候 return 1. 使用方法也很简单:

安装:

1
npm install webpack-fail-plugin

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var failPlugin = require('webpack-fail-plugin');
 
module.exports = {
    //config 
    plugins: [
        failPlugin
    ]
}
```
### 3.使用 done plugin
具体用法如下:
```javascript
// ...
plugins: [
// ...
function() {
this.plugin("done", function(stats) {
if (stats.compilation.errors && stats.compilation.errors.length) {
console.log(stats.compilation.errors);
process.exit(1);
}
// ...
});
}
// ...
],
// ...

4. 使用 webpack 2

不过 webpack 2 现在还在 beta 阶段,可以期待下。 (webpack 2 也仍然是使用 bail 参数)

Composer 使用技巧简述

最近使用了世界最好的语言 PHP 用来管理依赖关系的工具 Composer. 稍微做点记录, 以做备忘. 如有错误还望指出.

安装

1
2
3
4
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('SHA384', 'composer-setup.php') === 'aa96f26c2b67226a324c27919f1eb05f21c248b987e6195cad9690d5c1ff713d53020a02ac8c217dbf90a7eacc9d141d') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

上述代码来自官网.

局部安装

上述代码执行完成后, 只是下载到了 composer.phar 文件, 可以通过 php composer.phar 在任意位置执行.

全局安装

全局安装只是把 composer.phar 安装到 PATH 下即可. 可以像下面这样:

1
sudo mv composer.phar /usr/local/bin/composer

国内镜像加速

使用Composer中文网提供的中国全量镜像进行加速.

单项目加速

进入项目目录(即 composer.json 文件所在目录) 执行:

1
composer config repo.packagist composer https://packagist.phpcomposer.com

这条命令将在 composer.json 文件的末尾添加镜像加速配置:

1
2
3
4
5
6
7
"repositories": {
"packagist": {
"type": "composer",
"url": "https://packagist.phpcomposer.com"
}
}

全局加速

可以直接执行:

1
composer config --global repo.packagist composer https://packagist.phpcomposer.com

配置

参考 官方配置文档.

因为 composer 默认情况下, 会在使用的用户的家目录下生成 .composer 文件夹, 存放配置相关, 所以我们可以对这些部分进行配置.

1
2
3
composer config --global data-dir /www/.composer
composer config --global cache-dir /www/.composer
# cache-files-maxsize 也可以稍微大一点, 还有缓存时间

Auth 相关

Gitlab token 可以查看 https://docs.gitlab.com/ee/api/README.html#oauth-2-tokens

注意事项

type 配置为 gitlab, github 等时, 会优先通过 .composer/auth.json 文件中的配置来选择认证信息进行验证. 如果没有解决 Auth 认证相关问题, 可以使用普通的 vcs 例如 git 来使用.

Git workflow 详谈

作为一名工程师, Git 在日常开发中是不可或缺的工具。
这里详细介绍几种比较常用的基于 Git 的工作流模型, 以便于团队协作的规范化和效率提升。

中心化工作流

使用过SVN的应该都知道, SVN使用的是集中式管理流程, 如果你刚从SVN 切换到 Git , 你可以尝试使用中心化工作流的方式。这样,你几乎不需要变更之前的工作方式, 就可以完成平滑的过渡了。 而且在使用过程中还可以看到 Git 优于 SVN 的地方:
第一,每个成员都可以在本地拥有一份完整的项目代码仓库,而不只是一个工作区的副本,任何人都可以在本地执行 addcommit ,而不需要考虑远端仓库是否有变更,直到需要的时候再去提交即可。
第二,Git 的工作区、暂存区、引用更新等设计,可以给开发者更多自由来切换当前工作,且不会造成代码丢失。

工作细节

中心化工作流的方式是:在远端(远端可以是服务器端,也可以是本地的任意目录)新建一个仓库,默认是 master 分支,作为唯一的中心仓库。 所有人都 clone 这个仓库作为本地仓库,并在本地仓库进行开发。本地的提交是和远端仓库无关的,等需要的时候再 push 进主仓库的 master 分支即可。

在这种方式下, 远端是唯一确定的中心仓库, 所有人都要以这个仓库为准。 所以,在提交之前要先 fetch 最新提交,在这些提交之上作出自己的更改(一般我们使用 rebase来完成)。

如果本地的修改和远端仓库中的变更发生了冲突,那么 Git 会暂停 rebase ,并让你来解决这些冲突。我们可以很简单的使用 git statusgit add 等命令完成冲突的合并。 另外, 如果我们解决不了冲突, 我们也可以使用 git rebase --abort 很容易的退出 rebase 的过程。

这样每天的工作方式就变成了,从中心仓库拉取最新代码, 然后开始一天的工作, 开发完成后,拉取中心仓库的更新, 合并代码后, 再提交至中心仓库, 结束一天的工作。 这样的好处就是不需要变更原先(使用SVN)的工作方式。当然弊端也很明显,你并不知道中心仓库的代码是否是稳定的,或者说并不能确定当你的代码和中心仓库代码合并后,是否是稳定的,带来的问题就是开发进度和回滚不那么方便控制。

示例

我们有两位程序员, A 和 B, 两人同时在对一个项目做开发, 并且使用 Git 的中心化工作流方式。

1.创建远端中心仓库

这里我们有两种方式:

  • 借助于已经搭建好的平台 GitHub/GitLab 之类的,点击 create repo 即可。

  • 在远端(这里只是为了区别本地仓库,事实上,使用任何一个其他人可以连通的机器都可以,包括自己本地其他目录) 创建一个 裸仓库 ,创建裸仓库和我们平时创建本地仓库的区别,可以参考我另一篇文章 Git 本地仓库和裸仓库

这里以第二种方式为例:

1
2
# --bare 参数必须有
git init --bare /the/repo/path.git

2.所有人都 clone 中心仓库到本地作为本地仓库

1
git clone /the/repo/path.git

注意仓库地址必须是正确的, 且有权限访问才能 clone 成功。

3.程序员 A 在他的本地仓库进行功能开发并进行发布

一般情况下,我们通过 git status 看看当前状态,并通过 git addgit commit 等命令完成本地仓库的提交。 当然这个提交影响的也只是本地仓库而已,并没有对中心仓库产生任何影响,所以我们既不需要关心别人有什么提交,也不用担心我们当前的提交是否对别人造成了影响。当 A 认为自己所开发的功能已经完成, 那他将执行 git push origin master 这样的操作,将自己本地仓库所有不存在于中心仓库的提交都 push 到远端的中心仓库上。

4.程序员 B 在他本地仓库进行功能开发

B 在 clone 中心仓库后所做的操作和 A 一样,在本地仓库进行项目开发,并在本地仓库进行提交,他不需要知道中心仓库发生了什么样的变化。

5.程序员 B 将自己开发的功能并进行发布

B 在确认自己开发的功能已经完成后,想要将自己的代码通过 git push origin master 这样的操作发布至中心仓库,但是却被中心仓库提示他的修改已经和中心仓库有了分叉, 需要他先执行 git pull 之类的操作, 将中心仓库上 A 的提交与 B 本地的提交进行合并才允许他并入中心仓库。所以,他执行了 git pull --rebase origin master 来将中心仓库的修改并入他的本地仓库。使用 --rebase 参数的意义在于 fetch 执行完成后,将把 B 的所有提交移至 master 顶端。

当然这里不使用 --rebase 参数也会成功,只不过是会生成一个合并提交,有些情况下使用 --ff 参数也可以避免产生合并提交。在这里使用 --rebase 只是一个建议操作。

如果 A 和 B 修改的文件没有关联,一般情况下会直接完成合并,如果发生冲突,Git 将会暂停 rebase 的过程,并列出当前冲突的文件,你可以简单的使用 git statusgit add 等命令进行合并,合并后使用 git rebase --continue 继续 rebase 的过程。或者使用 git rebase --abort 退出 rebase 过程。

在 B 合并完成后,可以执行 git push origin master 将自己开发的功能发布至中心仓库。

至此,基础的中心化工作流方式就介绍完了,但是这里也很容易看出来其中的问题,除了前面说到过的以外,还有就是效率低下,如果很多人都在持续进行提交,那很影响新功能的提交(多人持续性进行提交)。 一个比较容易提升效率的方式就是切换到特性分支工作流的方式。

特性分支工作流

基于特性的分支工作流,可以为每个特性做隔离,避免对中心仓库主干代码造成影响。

工作细节

顾名思义, 就是根据每个特性都会开一个新的分支,每个分支都应该包含着描述性的名称,无论是一个人开发,还是多人协同,该特性的全部开发工作都在这个分支上进行。待该特性开发完成后, 并入主分支,然后删除分支,代码上线。

这种情况下, 最大的优势在于, 所有的特性开发都可以并行处理。 不必要像中心化工作流方式, 每个人的变动都可能引起其他的人的代码合并, 并且所有功能都杂糅在一起, 从测试和回滚都会变得很繁琐。 另外的一个好处就是特性分支可以推送到中心仓库,这样也便于单独测试。

这里需要注意的是,特性分支往主分支合并的时机,应该是该特性开发完成,并测试通过,避免对主干代码造成污染。

在进行分支隔离后,我们发现,我们当前只处理了开发模式,但并没有涵盖一个很完备的产品生命周期, 开发、发布、维护等过程,所以,我们有了 Gitflow 工作流。

Gitflow 工作流

基于Gitflow 的工作流方式, 这种工作流方式, 主要是管理着新功能开发,发布及维护等模式,根据不同类型的工作对分支进行定义, 分为 特性分支修复分支release 分支开发分支主分支

主分支:中心仓库建立后的默认 master 分支(当然使用其他分支也可以,但要保证该分支是受保护的)。主分支随时保持代码是稳定的,并且有明确的版本标签,后续代码回滚等操作都将从主分支进行。

开发分支:中心仓库建立后,从 master 分支切出来,此时与 master 分支保持一致。后续演进中,开发分支随时保持代码最新,但却不一定是线上实际运行的代码。

1
git checkout -b develop

特性分支:应该从开发分支切出,开发完成后, 再合并进入开发分支, 如果达到了发布标准, 则从开发分支切出 release 分支, 切出来的这个分支,只做该版本内的代码修复, 不再加入新功能, 这时此分支处于锁定的状态。

修复分支, 用于对线上主分支代码的及时修复, 待修复完成后, 合并进入主分支, 再并入开发分支。 修复分支只能从主分支切出。

发版分支, 一般命名为 release-xxx 这个分支只能从开发分支切出, 最后并入主分支,打上版本号的标签,它也应该并入开发分支,如果中间有其他修复的话。

fork 工作流

fork 分支流和上面介绍的所有工作流都不太一样。它的上游有一个唯一仓库, 所有人都是 fork 这个仓库, 在自己的远端和自己的本地各维护一个仓库,待开发完成后推入自己的远端仓库,并结合 GitHub/GitLab等提交 Pull Request,进入了 review 阶段,待通过后,将会被合并入上游唯一的仓库。这种方式比较适合 GitHub 中的大型开源项目, 对于小团队的内部项目, 这种方式可能未必合适。
而且 fork 工作流, 会占用更多的资源(毕竟每个人都维护一份远端仓库)。 而且每个人都看不到其他人的动态,只有当提交 Pull Request 的时候, 才知道每个人发生了什么。

总结

我个人比较推荐的是 Gitflow 的开发工作流, 这种方式下,一切都是可控的, 每个分支都有各自独立的功能,目的性很明确, 同时,在做代码回滚之类的操作也是可以直接剔除。 另外, 在这种工作流方式下, 团队中的每个人都能很轻易的知道其他人在做什么, 做出了什么样的改变, 对于团队协作, 或许更加合适。

当然所有的工作流并不一定能完全套用, 可以吸取一些规范, 合并入自己的日常工作, 将代码仓库的合作流程标准化和规范化, 这也是一切自动化的基础。

<全文完>

Git 本地仓库和裸仓库

通常我们会用 git init 命令来将我们所在的目录转换为一个 Git 本地仓库或者初始化一个新的空仓库。

用法

  • 将当前目录转换为一个本地仓库
1
git init

这个命令执行后会在本地生成一个 .git 的文件夹,用来追踪仓库的所有变更。效果如下:

git init

  • 指定某个目录成为本地仓库
1
git init <repo>

这个命令执行后, 将创建一个名为repo且只包含 .git 子文件夹的空目录。效果如下:

git init repo

  • 指定某个目录成为中心仓库(裸仓库)
1
git init --bare <repo>

这个命令执行后,将在本地创建一个名为 repo 的文件夹, 里面包含着 Git 的基本目录, 我们一般会将这个文件夹命名为后面加 .git 的形式,如 repo.git (这也是为什么我们从 GitHub clone 仓库的时候,地址都是 xxx.git 这样的形式的原因)。效果如下:

git init --bare repo.git

详细说一下使用 --bare 参数的含义,使用 --bare 参数初始化的仓库,我们一般称之为裸仓库, 因为这样创建的仓库并不包含 工作区 , 也就是说,我们并不能在这个目录下执行我们一般使用的 Git 命令。

对比

我们来对比一下直接使用 git init 创建的仓库和加了 --bare 参数的两个仓库。 我们直接看两个仓库的的 config 文件中的内容:

  • 直接 git init 创建的仓库:
1
2
3
4
5
6
7
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
  • 加了 --bare 创建的裸仓库:
1
2
3
4
5
6
[core]
repositoryformatversion = 0
filemode = true
bare = true
ignorecase = true
precomposeunicode = true

可以看到最直观的差异在于 bare 配置项是否为 true , 此外不加 --bare 创建的本地仓库配置中有一项 logallrefupdates = true , 作用根据名字就可以看出来, 记录所有的 ref (引用) 更新, 关于 ref 的部分之后有时间可以再写,这个配置可以理解为是 Git 的一道防线。

功能差异

我们可以使用最简单的例子演示一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 直接创建本地仓库
(Tao) ➜ git init repo
# 创建裸仓库
(Tao) ➜ git init --bare repo.git
# 分别 clone 两个仓库
(Tao) ➜ git clone repo c1
Cloning into 'c1'...
warning: You appear to have cloned an empty repository.
done.
(Tao) ➜ git clone repo.git c2
Cloning into 'c2'...
warning: You appear to have cloned an empty repository.
done.
# 进入 c1 仓库
(Tao) ➜ cd c1
(Tao) ➜ c1 git:(master) touch test
(Tao) ➜ c1 git:(master) ✗ g add -A
(Tao) ➜ c1 git:(master) ✗ g commit -m "test commit"
[master (root-commit) b1e32ad] test commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test
(Tao) ➜ c1 git:(master) git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 200 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error:
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error:
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To /Users/tao/repo
! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to '/Users/tao/repo'
# 进入 c2 仓库重复执行
(Tao) ➜ c1 git:(master) cd ../c2
(Tao) ➜ c2 git:(master) touch test
(Tao) ➜ c2 git:(master) ✗ git add -A
(Tao) ➜ c2 git:(master) ✗ git commit -m "test commit"
[master (root-commit) 7aacc58] test commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test
(Tao) ➜ c2 git:(master) git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 201 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To /Users/tao/repo.git
* [new branch] master -> master

从裸仓库 clone 下来的本地仓库可以进行正常的 push 操作, 但是从一般仓库 clone 下来的本地仓库却不行。 这也正是裸仓库存在的意义。 裸仓库一般情况下是作为远端的中心仓库而存在的。

总结

使用 git init --bare <repo> 可以创建一个裸仓库,并且这个仓库是可以被正常 clonepush 更新的, 裸仓库不包含工作区,所以并不会存在在裸仓库上直接提交变更的情况。

源码编译Vim 8

Vim 8.0 在2016.09.12发布了, 在各 Linux 发行版还没更新包的时候就源码编译来使用吧! 以 Debian 编译 Vim 为例.

简单编译截图

下载Vim 源码

可以在Vim 官网下载打包好的源代码.
或者使用 Git:

1
git clone https://github.com/vim/vim.git

编译

1
2
3
cd vim/src
./configure --with-compiledby="TaoBeier" --with-features=huge --enable-pythoninterp=yes --with-python-config-dir=/usr/lib/python2.7/config-x86_64-linux-gnu --enable-cscope --enable-perlinterp=yes --enable-rubyinterp=yes --with-luajit --enable-luainterp=yes --with-lua-prefix=/usr/include/lua5.1 --enable-multibyte --with-x --enable-fail-if-missing

上面的参数使用 ./configure --help 都可以看到对应用途. 上面使用的参数是增加了对 Python, Ruby, Perl, 以及X window的支持.

建议加上 --enable-fail-if-missing 参数, 以方便定位到哪里依赖缺失.

依赖

这里检查可能通不过, 首先是 lualuajit. 需要执行

sudo apt-get install lua5.1 liblua5.1-0 luajit libluajit-5.1-dev

其次注意 Python 的 config 位置.

最后就是 Perl 需要 sudo apt-get install libperl-dev.

最终

1
make && sudo make install

最终结果

完整编译截图

PS: 其实我一开始是想介绍 Vim 8 的, 然后碰巧在 GitHub 上有人问如何编译之类的, 就先写了这篇.

利器系列-更高效的Vim

这是利器系列第0篇, 当然要以每天我使用率最高的Vim来开始啦!

截图

screenshot.png

安装

(你需要一个有Python支持的Vim版本. 请使用 vim --version | grep +python 来检查)

  • 依赖(Debian/Ubuntu 平台)

    sudo apt-get install python vim exuberant-ctags git

    sudo pip install dbgp vim-debug pep8 flake8 pyflakes isort

  • 依赖(RedHat/CentOS 平台)

    CentOS 6.7的yum源自带的Python版本较旧,推荐自行安装Python2.7.

    sudo yum install python vim ctags git

    sudo pip install dbgp vim-debug pep8 flake8 pyflakes isort

  • 依赖(Mac OS 平台)

    brew install python vim git

    wget http://tenet.dl.sourceforge.net/project/ctags/ctags/5.8/ctags-5.8.tar.gz && tar -zxvf ctags-5.8.tar.gz && cd ctags-5.8 && ./configure && make && sudo make install

    sudo pip install dbgp vim-debug pep8 flake8 pyflakes isort

  • 下载vimrc 文件到用户主目录

    wget https://raw.githubusercontent.com/tao12345666333/vim/master/vimrc -O $HOME/.vimrc

  • 打开 Vim

    打开Vim, 它将会自动安装插件. 请耐心等待它完成. 或者你可以使用下面的命令来自行安装.

    vim -E -u $HOME/.vimrc +qall

  • 享受你的Vim并个性化它吧!

支持特性

插件管理(Vundle)

在这份配置中,使用了Vundle作为插件管理器. Vundle会自动接管 .vim 文件夹,所有配置好的插件将默认下载至~/.vim/bundle/, 在使用之前请确保.vim文件夹干净. Vundle的插件安装需要触发 git clone 操作,搜索需要 curl 支持.

配置(截取了部分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
" let Vundle manage Vundle
Bundle 'gmarik/vundle'
" ============================================================================
" Active plugins
" You can disable or add new ones here:
" Plugins from github repos:
" Python and PHP Debugger
Bundle 'fisadev/vim-debug.vim'
" Better file browser
Bundle 'scrooloose/nerdtree'
" Code commenter
Bundle 'scrooloose/nerdcommenter'
" Class/module browser
Bundle 'majutsushi/tagbar'
" Code and files fuzzy finder
Bundle 'kien/ctrlp.vim'
" Extension to ctrlp, for fuzzy command finder
Bundle 'fisadev/vim-ctrlp-cmdpalette'
" Zen coding
Bundle 'mattn/emmet-vim'
" Git integration
Bundle 'motemen/git-vim'
" Tab list panel
Bundle 'kien/tabman.vim'

支持操作

命令 解释
:PluginList 列出所有Plugin
:PluginInstall(!) 安装/更新Plugin
:PluginSearch(!) foo 搜索foo相关的Plugin
:PluginClean(!) 清理未使用的Plugin
:PluginUpdate 更新插件

工程文件浏览(NERDTree)

在这份配置中, 使用了NERDTree查看文件列表. 你可以在NERDTree中浏览和打开你文件系统中的目录或文件. 还可以进行文件隐藏和过滤, 设置添加书签等. 在NERDTree窗口输入?可获得操作指南. 这份配置中默认过滤掉了.pyc, .git, .hg, .svn等文件或文件夹的显示.

配置

1
2
3
4
5
6
7
8
9
10
11
12
" auto open or close NERDTree
autocmd vimenter * if !argc() | NERDTree | endif
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTreeType") && b:NERDTreeType == "primary") | q | endif
" NERDTree -----------------------------
" toggle nerdtree display
map <F3> :NERDTreeToggle<CR>
" open nerdtree with the current file selected
nmap ,t :NERDTreeFind<CR>
" don;t show these file types
let NERDTreeIgnore = ['\.pyc$', '\.pyo$']

支持操作

快捷键 解释
F3 打开/关闭NERDTree
,t 打开NERDTree并选中当前文件

语法检查

在这份配置中, 使用Syntastic插件进行语法静态检查. 包括但不限于C/C++/Go/Python/Haskell/Ruby/JavaScript等. 在本配置中对JavaScript的静态检查使用eslint,可以支持ES6及JSX等, 细节可以参考JSLint, JSHint和ESLint的对比及Vim配置, 想要切换检查工具只要修改对应位置即可.

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
" Syntastic ------------------------------
" show list of errors and warnings on the current file
nmap <leader>e :Errors<CR>
" turn to next or previous errors, after open errors list
nmap <leader>n :lnext<CR>
nmap <leader>p :lprevious<CR>
" check also when just opened the file
let g:syntastic_check_on_open = 1
" syntastic checker for javascript.
" eslint is the only tool support JSX.
" If you don't need write JSX, you can use jshint.
" And eslint is slow, but not a hindrance
" let g:syntastic_javascript_checkers = ['jshint']
let g:syntastic_javascript_checkers = ['eslint']
" don't put icons on the sign column (it hides the vcs status icons of signify)
let g:syntastic_enable_signs = 0
" custom icons (enable them if you use a patched font, and enable the previous
" setting)
let g:syntastic_error_symbol = '✗'
let g:syntastic_warning_symbol = '⚠'
let g:syntastic_style_error_symbol = '✗'
let g:syntastic_style_warning_symbol = '⚠'

特性

保存时自动进行语法静态检查,方便的错误提示及灵活的可扩展性.

支持操作

快捷键 解释
\e 打开错误列表
\n 移动到下一个错误位置
\p 移动到上一个错误位置

Git支持

在这份配置中, 使用vim-fugitivevim-signify做Git方面的支持. 可以进行常用的git操作及优雅的状态提示等(目前支持githg).

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
" Signify ------------------------------
" this first setting decides in which order try to guess your current vcs
" UPDATE it to reflect your preferences, it will speed up opening files
let g:signify_vcs_list = [ 'git', 'hg' ]
" mappings to jump to changed blocks
nmap <leader>sn <plug>(signify-next-hunk)
nmap <leader>sp <plug>(signify-prev-hunk)
" nicer colors
highlight DiffAdd cterm=bold ctermbg=none ctermfg=119
highlight DiffDelete cterm=bold ctermbg=none ctermfg=167
highlight DiffChange cterm=bold ctermbg=none ctermfg=227
highlight SignifySignAdd cterm=bold ctermbg=237 ctermfg=119
highlight SignifySignDelete cterm=bold ctermbg=237 ctermfg=167
highlight SignifySignChange cterm=bold ctermbg=237 ctermfg=227

支持操作

快捷键 解释
:Git [args] 类似执行git命令一样
:Gstatus 类似git status.在列表中使用-添加/移除文件
:Gcommit [args] 类似 git commit
:Gmerge [args] 类似 git merge
:Gpull [args] 类似 git pull
:Gpush [args] 类似 git push
:Gvdiff [revision] 类似 git push 但是会切分窗口

更多详细的操作可以使用 :help fugitive

Tag支持

在这份配置中,使用了Tagbar做Tag支持,可以显示当前文件中定义的类/变量等.

配置

1
2
3
4
5
6
" Tagbar -----------------------------
" toggle tagbar display
map <F4> :TagbarToggle<CR>
" autofocus on tagbar open
let g:tagbar_autofocus = 1

支持操作

快捷键 解释
F4 打开Tag列表

超全自动补全

在这份配置中, 使用了Neocomplcache作为主要的自动补全插件.

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
" NeoComplCache ------------------------------
" most of them not documented because I'm not sure how they work
" (docs aren't good, had to do a lot of trial and error to make
" it play nice)
" Disable AutoComplPop.
let g:acp_enableAtStartup = 0
" Use neocomplcache.
let g:neocomplcache_enable_at_startup = 1
let g:neocomplcache_enable_ignore_case = 1
" Use smartcase.
let g:neocomplcache_enable_smart_case = 1
let g:neocomplcache_enable_auto_select = 1
let g:neocomplcache_enable_fuzzy_completion = 1
let g:neocomplcache_enable_camel_case_completion = 1
let g:neocomplcache_enable_underbar_completion = 1
let g:neocomplcache_fuzzy_completion_start_length = 1
let g:neocomplcache_auto_completion_start_length = 1
let g:neocomplcache_manual_completion_start_length = 1
" Set minimum syntax keyword length.
let g:neocomplcache_min_keyword_length = 1
let g:neocomplcache_min_syntax_length = 1
let g:neocomplcache_lock_buffer_name_pattern = '\*ku\*'
" complete with workds from any opened file
let g:neocomplcache_same_filetype_lists = {}
let g:neocomplcache_same_filetype_lists._ = '_'
" <TAB>: completion.
inoremap <expr><TAB> pumvisible() ? "\<C-n>" : "\<TAB>"
" Define keyword.
if !exists('g:neocomplcache_keyword_patterns')
let g:neocomplcache_keyword_patterns = {}
endif
let g:neocomplcache_keyword_patterns['default'] = '\h\w*'
" Plugin key-mappings.
inoremap <expr><C-g> neocomplcache#undo_completion()
inoremap <expr><C-l> neocomplcache#complete_common_string()
" <C-h>, <BS>: close popup and delete backword char.
inoremap <expr><C-h> neocomplcache#smart_close_popup()."\<C-h>"
inoremap <expr><BS> neocomplcache#smart_close_popup()."\<C-h>"
inoremap <expr><C-y> neocomplcache#close_popup()
inoremap <expr><C-e> neocomplcache#cancel_popup()

支持操作

快捷键 解释
<Tab> 使用Tab键进行待提示项目选择
<C-g> 取消补全
<C-l> 完成待补全项中共同的字符串
<C-h> 关闭待选项
<C-y> 关闭待选项
<C-e> 退出待选项
<BS> 关闭待选项

类Tmux的窗口选择

在这份配置中,使用了vim-choosewin进行窗口管理器. 支持类Tmux的操作.

配置

1
2
3
4
5
6
" Window Chooser ------------------------------
" mapping
nmap - <Plug>(choosewin)
" show big letters
let g:choosewin_overlay_enable = 1

支持操作

快捷键 解释
- 开启窗口选择
- [ 选择上一个tab的窗口
- ] 选择下一个tab的窗口

更多操作可以使用 :help choosewin

灵活的Tab管理

在这份配置中使用了TabMan进行Tab管理,可以进行灵活切换与管理

配置

1
2
3
4
5
" TabMan ------------------------------
" mappings to toggle display, and to focus on it
let g:tabman_toggle = 'tl'
let g:tabman_focus = 'tf'

支持操作

快捷键 解释
tl 开启/关闭tab管理
tf 将光标移动到tab管理窗口

优雅的状态栏

在这份配置中,使用了Airline提供更多状态栏支持.

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
" Airline ------------------------------
let g:airline_powerline_fonts = 1
let g:airline_theme = 'bubblegum'
"let g:airline#extensions#tabline#enabled = 1
"let g:airline#extensions#tabline#left_sep = ' '
"let g:airline#extensions#tabline#left_alt_sep = '|'
let g:airline#extensions#whitespace#enabled = 1
" to use fancy symbols for airline, uncomment the following lines and use a
" patched font (more info on the README.rst)
if !exists('g:airline_symbols')
let g:airline_symbols = {}
endif
let g:airline_left_sep = ''
let g:airline_left_alt_sep = ''
let g:airline_right_sep = ''
let g:airline_right_alt_sep = ''
let g:airline_symbols.branch = ''
let g:airline_symbols.readonly = ''
let g:airline_symbols.linenr = ''

支持特性

可以显示分支,语法静态检查结果等.

自动插入头部

在这份配置中写了个小函数根据新建的不同类型的文件,自动插入头部,支持python, ruby, bash等.

Markdown实时预览

在这份配置中, 使用了vim-instant-markdownvim-markdown做Markdown格式的支持,可以支持实时预览等特性.

此功能需要有node环境支持,可以执行 npm -g install instant-markdown-d 进行安装.

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
" Vim-markdown ------------------------------
" Disabled automatically folding
let g:vim_markdown_folding_disabled=1
" LeTeX math
let g:vim_markdown_math=1
" Highlight YAML frontmatter
let g:vim_markdown_frontmatter=1
" Vim-instant-markdown -----------------
" If it takes your system too much, you can specify
" let g:instant_markdown_slow = 1
" if you don't want to manually control it
" you can open this setting
" and when you open this, you can manually trigger preview
" via the command :InstantMarkdownPreview
let g:instant_markdown_autostart = 0

支持操作

快捷键 解释
:InstantMarkdownPreview 手动触发markdown文件的预览

多游标选择、编辑等

在这份配置中, 可以在高亮某单词时, 通过使用 Ctrl-n 或者 Ctrl-p 进行多游标选择, 然后进行编辑或修改等操作.

快速文件查找

在这份配置中, 可以通过使用,R进行全文查找或者,r进行快速查找, 或者在当前字符串上使用,wR以及,wr来进行全文查找或者快速查找.

快速注释

使用NERDCommenter插件完成快速注释, 可以通过\ci进行快速注释.

Python 支持

完备的Python支持, 可以自动识别当前是系统环境或虚拟环境, 使用:Isort可智能对导入包进行排序, 使用:PymodeLintAuto可自动格式化.

除了上述列出的功能以外, 还有很多方便的特性,可以大大提升效率,在使用中慢慢体会吧!有问题可以在tao12345666333/vim on github 提issue

Python性能优化之工具篇

之前对公司的一个后端项目做了些性能优化, 学到一些值得记录的东西, 这篇主要是介绍在做性能分析时所用到的工具, 至于如何优化基本就是智者见智吧, 如果有时间可能会写的.

Python web应用程序的常见性能指标

此处忽略外部DNS解析等方面的性能
  • 响应时间
  • 错误率
  • 吞吐率
  • 执行时间
  • 内存占用

Python 性能分析工具

##TODO