Git 项目管理
2021-04-07
Git Flow
荷兰程序员 Vincent Driessen 2010 年提出。
PDF 下载
- master 主干
- develop 开发分支
- feature/xxx 功能开发分支(临时)
基于 develop 创建,开发完成之后:合并到 develop 分支,删除
- release/xxx 预发布分支(临时)
基于 develop 创建,测试通过之后:合并到 master 分支,打 tag,合并到 develop 分支,删除
- hotfix/xxx 问题修复分支(临时)
基于 master 创建,问题修复之后:合并到 master 分支,打 tag,合并到 develop 分支,删除
特点:基于版本交付
PS: 作者于 10 年后,也就是 2020 年,更新了一次,表示:对于互联网应用的开发应该考虑更加简单的工作流,比如 GitHub Flow。但不管怎样,应该结合自身的实际情况,不能盲目照搬。
GitHub Flow
- 从 master 拉分支,提交,推送
- pull request
- 评审,测试
- merge 到 master
特点:基本不涉及项目的分支管理,主要是对多人协作方式提出建议:Pull Request。适合多人参与的开源项目,由项目管理员负责维护主干。
中间可以借助自动化工具来静态分析、部署、测试,提升开发速度。但这些工具不是 GitHub Flow 专有,或者说不是它的特色。
这套逻辑看似非常简单,但要硬套到企业项目开发流程中可能会非常复杂,水土不服。
PS: 虽然 git 新增了一个 request-pull 子命令,但可能很鸡肋,不可能脱离 Web 来参与讨论、评审代码。
GitLab Flow
分不同环境:
- master 开发分支,管理方式就是 GitHub Flow,不过就是 Pull Request 改名为了 Merge Request
- pre-production 预发布分支,只能从 master 合并
- production 发布分支,只能从 pre-production 合并
如果需要发布:
- 从 master 拉分支,比如:
20-04-stable
,创建语义化版本号。
- 如果后期有严重 BUG,可以从 master cherry-pick 过来。
特点:比 GitHub Flow 更进一步,对项目的发布和部署提出了建议,并支持多个环境。
主要是其中有一点特别好的就是: Upstream First, 上游优先。所有环境以及维护分支的提交必须来自 master 分支。
我的思考
当然,还是那句老话:适合自己的就是最好的。
项目分支管理流程要和项目自身的特点,以及团队成员的技术水平相匹配。
Git Flow 的整套流程挺完备的,符合一般开发的习惯,只是对其作出规范而已。
GitHub Flow 也好,GitLab Flow 也好,都可以看做是 Git Flow 的补充。
GitHub Flow 和 GitLab Flow 都假定 master 分支是可发布的,而 Git Flow 从 master 拆分出了一个 develop 作为缓冲,我认为这个设计比较合理。
Git Flow 有几个需要注意的问题:
- 合并的时候保留之前的合并记录,谨慎快进 (
--no-ff
)
- hotfix, release 分支推送到 master 发布之后,切记还要同步推送到 develop 分支
- 必须坚持 master, develop 上不随意推送(还是得靠 Pull Request 机制)
- 如果有不属于当前发布周期需要的开发,不要合并到 develop
- 临时分支必须快用快销,不要长时间保留,且合并之后理解删除
我设想中的开发流程
1,基本参照 Git Flow (借助工具)
上游优先原则:master 分支作为所有可发布环境的上游
2,自动化测试:
- develop, release, master: 只要有变更就触发一次自动化测试
- 此外, master 应该保持一定频率的定时自动化测试
3,老版本需要维护就在 tag 上拉分支。
现实场景中,可能要为 abc 环境上的某个老版本 v1.0.0 修复 BUG、加功能,或对已有功能进行一些调整。
git branch maintain/abc v1.0.0 # 一旦分叉,就需要长期保留该分支
# maintain/abc/develop
# maintain/abc/feature/xxx
# maintain/abc/hotfix/xxx
# maintain/abc/release/xxx
# 视情况,可以简化处理,不用上面这些分支
PS: 最后需要重新发布的时候可以对版本号加上附加的标识 v1.0.0.1.abc
5,如果是 OEM,针对客户有关的信息、资源应该留给打包系统来统一处理
此外:
- 项目应有明确的 roadmap
- 代码评审
- 数据库设计统一管理
- 项目文档,需求库,用例库
- 版本号基本上遵循语义化版本规范
- 提交记录遵循 git commit message 规范 (借助工具)
- CI/CD + 自动化测试
参考资料与拓展阅读
- 阮一峰, Git分支管理策略
- 阮一峰, Git 工作流程
- git-flow 备忘清单
- GitLab, Introduction to GitLab Flow
- GitHub, Understanding the GitHub flow
- GitHub, GitHub Flow
- Git-Tower, git-flow 的工作流程
- 阮一峰, Git 使用规范流程
- 阮一峰, Commit message 和 Change log 编写指南
- 阮一峰, git cherry-pick 教程
- 阮一峰, Git远程操作详解
- 阮一峰, git bisect 命令教程
- 阮一峰, 常用 Git 命令清单
- 廖雪峰, Git教程
- https://github.com/wangdoc/git-tutorial
LinuxNetwork 网络管理 iptables
2021-04-04
命令参数
iptables -[ACD] chain rule-specification [options]
iptables -I chain [rulenum] rule-specification [options]
iptables -R chain rulenum rule-specification [options]
iptables -D chain rulenum [options]
iptables -[LS] [chain [rulenum]] [options]
iptables -[FZ] [chain] [options]
iptables -[NX] chain
iptables -E old-chain-name new-chain-name
iptables -P chain target [options]
链相关
--new -N [chain]
链:创建
--delete-chain -X [chain]
链:删除
--rename-chain -E old-chain new-chain
链:更名
--list -L [chain [rulenum]]
列出指定链或所有链中的所有规则(表格形式)
--list-rules -S [chain [rulenum]]
同上,不过是按照规则定义的格式列出 很好用
--flush -F [chain]
清空规则
--zero -Z [chain [rulenum]]
计数器清零(数据包计数器,流量计数器)
--policy -P chain target
修改策略
规则相关
--append -A chain rule-specification
附加规则
--check -C chain rule-specification
检查规则是否存在
--delete -D chain rule-specification
删除匹配规则
--delete -D chain rulenum
删除 指定序号的 规则
--insert -I chain [rulenum]
插入到指定位置(默认插入到第一个)
--replace -R chain rulenum
替换 指定序号的 规则
规则说明
常用命令
查看
sudo iptables -S
sudo iptables -t nat -S POSTROUTING
sudo iptables -nL
sudo iptables -nL INPUT
sudo iptables -nL --line-numbers
sudo iptables -Z
sudo iptables -Z INPUT
sudo iptables -Z INPUT 1
# 如果是这么定义的话:
# -A INPUT -m conntrack --ctstate INVALID -j DROP
sudo iptables -D INPUT -m conntrack --ctstate INVALID -j DROP
sudo iptables -D INPUT 3
访问拦截
# 对指定端口放行
sudo iptables -I INPUT -p tcp --dport 1022 -j ACCEPT
# 禁止来自无线网络的流量访问某端口(突发奇想的一个小例子)
sudo iptables -A PREROUTINE -i wlp6s0 --dport 22 -j DROP
NAT
iptables -t nat -A POSTROUTING -d 192.168.0.102 -j SNAT --to 192.168.0.1
iptables -t nat -A PREROUTING -d 202.202.202.2 -j DNAT --to-destination 192.168.0.102
iptables -t nat -D PREROUTING -p tcp --dport 8080 -i eth2.2 -j REDIRECT --to 80
对指定流量打标记
内核可以给这个包加上一个标记(可能存在包的数据结构中,总之,只对本地环境有效),可以实现流量的统计、限制等其他复杂的控制。
标记值最大可以到 2^32
iptables -t mangle -A PREROUTING -s 192.168.1.3 -j MARK --set-mark 60
iptables -t mangle -A PREROUTING -p tcp --dport 22 -j MARK --set-mark 2
//打标记
iptables -t mangle -A PREROUTING -j MARK --set-mark 33
//匹配标记
iptables -t nat -A PREROUTING -m mark --mark 33 -j ACCEPT
//or-mark
iptables -t mangle -A PREROUTING -j MARK --or-mark 0x400
//掩码匹配
iptables -t nat -A PREROUTING -m mark --mark 0x400/0x400 -j ACCEPT
iptables -t mangle -A INPUT -m state --state NEW -j MARK --set-mark 1
iptables -t mangle -A INPUT -j CONNMARK --save-mark
iptables -t mangle -A INPUT -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -mttl --ttl-eq 64 -j MARK --set-mark 10
iptables -t mangle -A PREROUTING -mttl --ttl-eq 123 -j MARK --set-mark 20
iptables -t filter -A FORWARD -m mark--mark 10 -j ACCEPT
iptables -t filter -A FORWARD -m mark--mark 20 -j DROP
iptables -t mangle -A QOS_MARK_FORWARD_eth1 -j CONNMARK --restore-mark --nfmask 0xfffff --ctmask 0xfffff
iptables -t mangle -A QOS_MARK_FORWARD_eth1 -m mark --mark 0x0/0xfffff -j QOS_RULES_FORWARD_eth1
iptables -t mangle -A QOS_RULES_FORWARD_eth1 -j CONNMARK --save-mark --nfmask 0xfffff --ctmask 0xfffff
iptables -t mangle -A POSTROUTING -m iprange --src-range 192.168.0.2-192.168.0.200 -j MARK --or-mark 0x1
-m mark
-m connmark
-j MARK
-j CONNMARK
-j CONNSECMARK
-j SECMARK
--set-mark value
设置nfmark值
--and-mark value
nfmark与value与运算
--or-mark value
nfmark与value或运算
匹配
iptables -t mangle -A INPUT -m mark --mark 1
限速
思路:hashlimit 模块
屏蔽指定网站
利用 string 模块 (xt_string.ko
) 做域名匹配:
sudo iptables -A OUTPUT -m string --string baidu.com --algo bm -j LOG --log-prefix "iptables-test:blocked:baidu.com: "
sudo iptables -A OUTPUT -m string --string baidu.com --algo bm -j DROP
sudo iptables -vnL
curl https://www.baidu.com/
tail -f /var/log/syslog | grep "iptables-test"
sudo iptables -F OUTPUT
sudo iptables -A FORWARD -m string --string baidu.com --algo bm -j LOG --log-prefix "iptables-test:blocked:baidu.com: "
sudo iptables -A FORWARD -m string --string baidu.com --algo bm -j DROP
HTTPS 居然也可以生效,其原理我还不清楚,到底是匹配到了包的哪一部分包含了 baidu.com 呢?
提示:
- 这个规则也可以放到 INPUT 链上。
- 如果加上
-p tcp –dport 80
可能更加精确,免得别的什么包里面包含了 baidu.com 被拦截。
- 可以加多个 string 参数。
如果是 HTTP 的话,在我的理解范围之内,可以做到更细致的匹配,比如匹配到路径,甚至 Cookie。
string match options:
--from Offset to start searching from
--to Offset to stop searching
--algo Algorithm
--icase Ignore case (default: 0)
[!] --string string Match a string in a packet
[!] --hex-string string Match a hex string in a packet
algo 的选项:bm, kmp,参考 man iptables-extensions
。
参考资料与拓展阅读
LinuxNetwork 网络管理 iptables
2021-04-03
iptables 的历史变更,发展趋势,和其他技术的关联我也曾花了不少时间去了解,可以说还是很不全面,就不献丑了(或者以后再来说说)。
这里就单单讲一下 iptables。
基本思想
在网络数据传输过程中有几个关键点埋上钩子,每个钩子上绑定了一个规则链(CHAIN)。
我们在这些链上注册一些处理规则(RULE),也就是 条件 加 操作。
网络包走到埋点的地方时,内核会逐个规则检查,如果符合条件就会执行预定操作。
此外:
- 这些处理规则按照不同类型,分成了五类,存在五张不同的表中。
- 每个规则链可以设置一个预定的操作(文档中称之为:策略 Policy)。
五个点
PREROUTING
路由:内核收到网络包之后,判断该包是否是自己的,应该给哪个程序
INPUT
用户程序收到包之前(内核判断是自己的包之后,传输到用户程序)
OUTPUT
程序往外发包
FORWARD
这个包不是自己的,然后需要中转出去
POSTROUTING
路由:系统判断该包应该怎么发出
PS:可以自定义新的链,然后再别的链中引用。我所处理的任务都没有到需要创建新链的地步,所以没有接触过。
五张表
应该说是五个功能。
- filter 过滤,即判断这个包。默认
- nat 地址转换
- mangle 数据包修改,日常网络管理应该不会用到
- raw 数据包修改(在内核处理之前)
- security unknown
操作类型
ACCEPT
放行
DROP
拦截
REJECT
拦截,但是告知对方
MARK
加标记
NAT
SNAT
源地址转换
DNAT
目的地址转换
REDIRECT
端口转换
参考资料与拓展阅读
Golang
2021-04-01
类似代码:
for _, f := range files {
fp, err := os.Open(f)
if err != nil {
panic(err)
}
defer fp.Close()
// do something
}
Goland 提示:possible resource leak,'defer' is called in the 'for' loop
defer
是在最后函数退出时执行,但是变量已经经过循环覆盖,可能会导致内存泄漏。
似乎 Golang 的 defer 还是不够聪明。
换种写法:
for _, f := range files {
func () {
fp, err := os.Open(f)
if err != nil {
panic(err)
}
defer fp.Close()
// do something
}()
}
Golang
2021-03-30
- GORM
- ent
- Xorm 转到Gitea
- Bun
- Reform
- GoRose
GitHub 搜索结果
- go-gorm/gorm
The fantastic ORM library for Golang, aims to be developer friendly
- ent/ent
An entity framework for Go
- geektutu/7days-golang
7 days golang programs from scratch (web framework Gee, distributed cache GeeCache, object relational mapping ORM framework GeeORM, rpc framework GeeRPC etc) 7 天用 Go 动手写/从零实现系列
- gogf/gf
GoFrame is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
- sqlc-dev/sqlc
Generate type-safe code from SQL
- go-xorm/xorm
Simple and Powerful ORM for Go, support mysql,postgres,tidb,sqlite3,mssql,oracle, Moved to https://gitea.com/xorm/xorm
- volatiletech/sqlboiler
Generate a Go ORM tailored to your database schema.
- go-pg/pg
Golang ORM with focus on PostgreSQL features and performance
- go-gorp/gorp
Go Relational Persistence - an ORM-ish library for Go
- xo/xo
Command line tool to generate idiomatic Go code for SQL databases supporting PostgreSQL, MySQL, SQLite, Oracle, and Microsoft SQL Server
- upper/db
Data access layer for PostgreSQL, CockroachDB, MySQL, SQLite and MongoDB with ORM-like features.
- uptrace/bun
SQL-first Golang ORM
- xxjwxc/gormt
database to golang struct
- steebchen/prisma-client-go
Prisma Client Go is an auto-generated and fully type-safe database client
- xormplus/xorm
xorm 是一个简单而强大的 Go 语言 ORM 库,通过它可以使数据库操作非常简便。本库是基于原版 xorm 的定制增强版本,为 xorm 提供类似 ibatis 的配置文件及动态 SQL 支持,支持 AcitveRecord 操作
- go-reform/reform
A better ORM for Go, based on non-empty interfaces and code generation.
- gobuffalo/pop
A Tasty Treat For All Your Database Needs
- bobohume/gonet
go 分布式服务器,基于内存 mmo
- unionj-cloud/go-doudou
go-doudou(doudou pronounce /dəudəu/)is OpenAPI 3.0 (for REST) spec and Protobuf v3 (for grpc) based lightweight microservice framework. It supports monolith service application as well.
- gohouse/gorose
GoRose(go orm), a mini database ORM for golang, which inspired by the famous php framwork laravle's eloquent. It will be friendly for php developer and python or ruby developer. Currently provides six major database drivers: mysql,sqlite3,postgres,oracle,mssql, Clickhouse.
- huandu/go-sqlbuilder
A flexible and powerful SQL string builder library plus a zero-config ORM.
Golang
2021-03-29
httpbin 是我练手的一个非常简单的小项目,功能就是:
1. HTTP POST 请求 (POST /
) 提交一个字符串,服务器返回一个 ID。
1. HTTP GET 请求 (GET /xxxx
),返回 ID 对应的字符串。
计算机网络 Linux
2021-03-15
早几年前,Linux 系统的网卡名称都是 eth0、wlan0,后来都变了个风格,就拿我的电脑举例:enp7s0, wlp6s0。
这到底是是什么原因呢?
最近突然好奇,去查了资料才知道为什么。
在 Fedora 的技术资料中找到,这个和 Systemd 有关,然后又在 freedesktop 官网 Systemd 的手册中找到了详细的说明。
现在的命名方案有好长一段,估计要看个半个小时(如果感兴趣可以仔细阅读一下),解开我的疑问却不需要那么复杂。
Linux DEB
2021-03-13
输出 dot 格式的包依赖关系图,可以用 graphviz 生成图片。
个人
2021-03-11
开发工具 密码学 OTP Auth 信息安全
2021-03-08
基础概念
身份验证器
Authenticator
密码就算是身份验证器。
加密密钥,比如 SSH 的公钥私钥(密钥对)
动态密码
One-time Password, 缩写: OTP, 又叫做一次性密码
我们常用的的短信验证码就是一种非常方便快捷的动态密码形式。
早些年一些网络服务,比如谷歌、网易通行证等,可能会提供一个动态口令表,包含十几个密码,可以保存为图片,或者纯文本,上面的密码可以逐个使用,每个密码只能用一次。
- RFC4226 HOTP: An HMAC-Based One-Time Password Algorithm
- RFC6238 TOTP: Time-Based One-Time Password Algorithm
HOTP 基于 HMAC 算法
简单来说就是根据密钥和计数器来生成一个一次性密码。
除了记住密钥之外,你还要记住这是第几次使用。
- HOTP value = HOTP(K, C) mod 10d
- HOTP(K, C) = truncate(HMACH(K, C))
- truncate(MAC) = extract31(MAC, MAC[(19 × 8) + 4:(19 × 8) + 7] × 8)
MAC[(19 × 8) + 4:(19 × 8) + 7] × 8
取第十九字节的后四位(小端序), 转成一个有符号整型数(小端序),作为截取 MAC 的位置
- extract31(MAC, i) = MAC[i × 8 + 1:i × 8 + (4 × 8) − 1]
MAC[i × 8 + 1:i × 8 + (4 × 8) − 1]
从上一步得到的位置处,取四个字节,去掉符号位(小端序)
TOTP 基于时间
- 协商起始时间 T0 和时间间隔 TX
- 双方分别计算时间计数器 CT
- TOTP value(K) = HOTP value(K, CT)
多重要素验证
Multi-factor authentication, 缩写: MFA
Two-factor authentication, 缩写: 2FA
谷歌身份验证器
Google 身份验证器是一款 TOTP 与 HOTP 的两步验证软件令牌,此软件用于 Google 的认证服务。此项服务所使用的算法已列于 RFC 6238 和 RFC 4226 中。
Google 身份验证器给予用户一个六位到八位的一次性密码用于进行登录 Google 或其他站点时的附加验证。其同样可以给第三方应用生成口令,例如密码管理员或网络硬盘。先前版本的 Google 身份验证器开放源代码,但之后的版本以专有软件的形式公开。
谷歌验证器基于 TOTP,但是更进一步简化,以约定代替了协商过程。
- T0 为 Unix 时间
- TX 为 30 秒
- 哈希算法为 sha1
此外:
虽然不是很大的创新,而且这个软件验证器实现很简单,但是免费、开放(不需要做任何谷歌服务绑定),加上谷歌的强大影响力,这个软件验证器被很多系统采用。
最后,其他提供动态口令的应用都需要来兼容谷歌身份验证器。
PS: RedHat 开发并维护了开源的 FreeOTP 分支项目。
PS: 微软也有一个 Microsoft Authenticator,阿里云 APP 中有一个 虚拟MFA 功能,都是一个意思。
微软家的为自己提供 8 位密码,别人家的就 6 位,区别对待(虽然感觉好像也并没有什么影响)
阿里云 MFA 是需要手机 APP 登录进去之后才能使用的。
Just4Fun
import base64
import hashlib
import hmac
import time
DEFAULT_INTERVAL = 30 # Google Authenticator: 30 秒
DEFAULT_HASH = hashlib.sha1
def get_hotp_token(secret: str, counter: int, hash_algorithm=DEFAULT_HASH, length=6):
padding_len = 8 - len(secret) % 8
if padding_len != 8:
assert 1 <= padding_len <= 7
secret += '=' * padding_len
key = base64.b32decode(secret, True)
message = (counter & 0xffffffffffffffff).to_bytes(8, 'big')
mac = hmac.new(key, message, hash_algorithm).digest()
loc = mac[-1] & 0x0F
token = (int.from_bytes(mac[loc:loc+4], 'big') & 0x7fffffff) % (10 ** length)
return token
def get_totp_token(secret, interval=DEFAULT_INTERVAL):
time_counter = int(time.time()) // interval
return get_hotp_token(secret, time_counter)
if __name__ == '__main__':
print('%06d' % get_totp_token(sys.argv[1]))
参考资料与拓展阅读