git rebase

简介

在Git中,用两种方法将两个不同的branch合并。一种是通过git merge,一种是通过git rebase。然而,大部分人都习惯于使用git merge,而忽略git rebase。本文将介绍git rebase的原理、使用方式及应用范围。

git merge 做些什么

当我们在开发一些新功能的时候,往往需要建立新的branch。

在上图中,每一个绿框均代表一个commit。除了c1,每一个commit都有一条有向边指向它在当前branch当中的上一个commit。

图中的项目,在c2之后就开了另外一个branch,名为experiment。在此之后,master下的修改被放到c4 commit中,experiment下的修改被放到c3 commit中。

如果我们使用merge合并两个分支
$ git checkout master
$ git merge experiment

得到的commit log如下图所示

我们看到,merge所做的事情实际上是:

  1. 首先找到masterexperiment中最新的commit的最近公共祖先,在这里就是c4c3的最近公共祖先c2
  2. experiment分支上在c2以后的所有commit合并成一个commit,并与master合并
  3. 如有合并冲突(两个分支修改了同一个文件),首先人工去除重复。
  4. 在master上产生合并后的新commit

git rebase做些什么

rebase所做的事情也是合并两个分支,但是它的方式略有不同。基于上例描述,rebase的工作流程是

  1. 首先找到masterexperiment中最新的commit的最近公共祖先,在这里就是c4c3的最近公共祖先c2
  2. experiment分支上在c2以后的所有commit*全部移动到*master分支的最新commit之后,在这里就是把c3移动到c4以后。

由于git的每一个commit都只存储相对上一个commit的变化(或者说是差值,delta)。我们通过移动c3到master,代表着在master上进行c3相应的修改。为了达成这一点,只需在experiment分支上rebase master
$ git checkout experiment
$ git rebase master

需要注意的是,rebase并不是直接将c3移动到master上,而是创建一个副本。我们可以通过实际操作发现这一点。在rebase前后,c3的hash code是不一样的。

rebase前的commit log是
* 1b4c6d6 (master) <- c4
| * 66c417b (experiment) <- c3
|/
* 972628d

rebase后的commit log是
* d9eeb1a - (experiment) <- c3'
* 1b4c6d6 - (master) <- c4
* 972628d

可以发现c3的hash code从66c417b变到了d9eeb1a

在这之后,我们只需要在master上进行一次前向合并(fast-forward merge)
$ git checkout master
$ git merge experiment

rebase之后的commit log呈线性,更加清晰。此时如果experiment分支不再被需要,我们可以删除它。
$ git branch -d experiment

何时使用

我们一般只在本地开发的时候rebase一个自己写出来的branch。

谨记,千万不要rebase一个已经发布到远程git服务器的分支。例如,你如果将分支experiment发布到了GitHub,那么你就不应该将它rebasemaster上。因为如果你将它rebasemaster上,将对其他人造成麻烦。

总结

git rebase帮助我们避免merge带来的复杂commit log,允许以线性commit的形式进行分支开发。

谈谈抓取与反抓取

抓取是采集竞品或其它源网站数据,反抓取就是防止别人的抓取行为。目前来说,没有一家公司在反抓取方面做的比较好。举个例子,搜狗运维部门用机器学习搞反抓取策略,在业界也挺得意的,被我花了一周攻克,只用了四十个IP,一天请求上百万,两个多月了,照样好好的用着。
业界反抓取无非以下几种策略:
1. 按照请求频率封禁IP(现在只有比较low的公司会用这种,这种方法的负面伤害更大)
2. 按照IP和请求头部(agent 等信息)封禁
3. 通过执行Javascript程序注入动态cookie
4. 通过机器学习策略分析用户行为
5. 探测到用户有抓取行为,丢一些假数据给用户,比如某地图商
主流是第三种和第四种,第三种的门槛主要是是需要渲染JS才能得到正确的cookie,而普通抓取程序不具备这个功能,并且渲染JS速度太慢,在大规模抓取中不适用。但是第三种我有一套解决方案,是cookie分发机制,出于一些考虑,这套技术不做分享。(在搜狗公共号抓取中,使用cookie分发机制,四十IP可以做到10个/s 请求速度而不遭遇封禁)

第四种那就要好好伪装自己的请求了,比如请求的refer、user-agent、请求的文件类型等,需要自己去做随机请求,难度不大。

抓取解析,那就太简单了,分析DOM结构、使用正则等等,看你具体使用场景吧。

 

awk使用

awk 处理数据挺方便的,整理下使用方法。

先看下最简单的用法

下面是数据,文件名pic.csv

10371029    130657404  33250828600
10375462   0  32754488348
10401830   130670653  33301943326
10490532   130818323  33390650001,33390638503
10492736   130808000  33392915994,33392923278,33392951671,33392965894
10501933   130847315  33426734671,33426784141,33426741368
10520323   130871605  33474622551
10561441   130900744  33569740772
10563686   130931058  33572560455,33572597666,33572625609
10594334   130933942  33595945445,33595930712
10609164   130968431  33625612546
10623734   130960850  33655945376
10625513   130985226  33659411835,33659434639
10662700   131036062  33748007817
10688362   131050019  33802663455
10744503   131143877  33909572401,33909557630
10749313   131138769  33912184752
10777611   131181015  33975768553
10790647   131192937  34013919173,34013904105,34013909379
10790833   131198786  34014605153,34014654005,34014895558,34014920756
10799709   131213531  34039005481
10805941   131221289  34048620033,34048637653
10806145   131228025  34049593438,34049617769,34049618566,34049596717
10837378   131259345  34138112374,34138156606
10847268   131293940  34163393641,34163387864

只看前两列

awk '{print $1,$2}' pic.csv

数据过滤,只看第一列数字为10847268

awk ' $1==10847268' pic.csv

内建变量
说到了内建变量,我们可以来看看awk的一些内建变量:

$0 当前记录(这个变量中存放着整个行的内容)
$1~$n 当前记录的第n个字段,字段间由FS分隔
FS 输入字段分隔符 默认是空格或Tab
NF 当前记录中的字段个数,就是有多少列
NR 已经读出的记录数,就是行号,从1开始,如果有多个文件话,这个值也是不断累加中。
FNR 当前记录数,与NR不同的是,这个值会是各个文件自己的行号
RS 输入的记录分隔符, 默认为换行符
OFS 输出字段分隔符, 默认也是空格
ORS 输出的记录分隔符,默认为换行符
FILENAME 当前输入文件的名字

awk  -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd
root    0       /root
bin     1       /bin
daemon  2       /sbin
adm     3       /var/adm
lp      4       /var/spool/lpd
sync    5       /sbin

如果把文件第一列用逗号分隔,可以用

awk 'ORS="," {print $1}' pic.csv