不以引进正版为理由的打击盗版都是文化审查。
公开的 BT 站点,请当心 DMCA 钓鱼。
拥有500万验证种子文件。
rss
广告很多,记得开启浏览器的广告屏蔽插件,AdBlock, uBlock。
私有的 Private tracker
最后如果有很多 PT 站,推荐 PT Plugin Plus 这个浏览器扩展来管理。
这是我再次开始关注 PT 时,注册的第一个网站。
迄今为止用过的最舒服的 PT 站。
没有考核,速度最快,所以完成后我也会挂很长时间。
SceneTime 是一个0day/Scene综合PT站,目前存活种子数80000。
自从有了 AvistaZ 就不怎么用了。
一个没有那么活跃,但是种子数量很多。
非常活跃,但平时不怎么用
比较早的时候使用比较多,现在也还是不错的,成长比较快的一个站点。推荐。
感谢好心人邀请,也是一非常大的站点。不过free电影比较少,基本是 50%
阅读,听书是其特色。
0-day
[[AvistaZ]] 以前叫 AsiaTorrent,是一个东亚、东南亚、南亚的电影、电视剧、音乐的PT,主要还是中日韩加上港台的资源最多,高清和DVD资源都很多。有10万用户、3万种子,是一个比较活跃的高清电影等综合资源的PT站点。在注册使用一段时间之后,已经主要使用该网站来看日韩剧了。
重在亚洲的影视资源。可我还没有账号,求邀请。感谢好心人给我邀请,再次感谢 🙏🏻️.
暂时无账号,求大佬邀请。
OpenCD 是一个主打音乐的站点,比较想进,但是一直没有机会,所以只能进了 jpopsuki,日韩音乐比较多。主要挺 kpop 的我,目前感觉还行。如果有人有 OpenCD 邀请有求一枚。
听说是挺大的站,求邀请吧
主打高清的,不怎么用。
Spring AOP 指的是 Aspect Oriented Programming(面向切面编程),AOP 是一种编程范式,AOP 提供了不同于 OOP 的另一种全新的软件架构思考方式,目的是为了通过分离切面问题来增加程序的模块化,同通俗的话讲就是不修改代码的情况下给程序增加额外的行为。Spring AOP 就是这样一个框架,可以提高我们切面编程的效率。
Spring AOP 的几个常用的使用场景:
Spring 中有两种方式来使用 AOP
在深入 AOP 之前,先来了解一些关键性的术语:
join-point
: 中文通常翻译成切点,切入点,也就是切入的地方,通常是一个方法 a point during the execution of a program, in spring AOP always represents a method executionpointcut
:is a predicate or expression that matches join-pointadvice
: 具体切入的动作 actions taken by aspect at a particular join-point, is associated with a pointcut expression and runs at any join point matched by the pointcutweaving
: linking aspects with other application types or objects to create an advised object.基于上面的认知,知道 join-point 可以认为是方法调用的时刻,所以 Spring 中有 5 种类型的 Advice 时机:
Before advice
, 方法执行前(无法阻止方法执行,除非抛出异常)After returning advice
, 正常方法(无异常)返回后执行After throwing advice
, 抛出异常时执行After advice
, 不管方法正常或者抛出异常后执行Around advice
, 方法调用前后Spring 中 AOP 的实现主要是通过 JDK [[动态代理]]和 [[CGLIB]] 动态代理完成。1可以通过注解 [[Spring @EnableAspectJAutoProxy]] 的参数来指定。
InvocationHandler
和 Proxy
类引入依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
在启动类上使用 [[Spring @EnableAspectJAutoProxy]] 注解,但其实如果不配置该注解,spring.aop.auto
属性也是默认开启的。
Spring Boot 中指定 CGLIB 实现 AOP。
在注解中指定:
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {}
或者配置属性:
spring.aop.proxy-target-class=true
具体的版本可以自行搜索使用。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
@Aspect
注解将 Java 类定义为切面,使用 @Pointcut
定义切点。
在不同的位置切入,可以使用 @Before
, @After
, @AfterReturning
, @Around
, @AfterThrowing
等等。
@Before
,在方法执行前执行@After
,方法执行后执行@AfterReturning
,方法返回结果之后执行 [[Spring AOP AfterReturning]]@AfterThrowing
,异常通知,方法抛出异常之后@Around
,环绕方法执行如何定义切点,以及切点表达式的编写是学习 AOP 的一个重点。
Pointcut expression 由一个 pointcut designator(PCD) 开头,来告诉 Spring 什么时候匹配。Spring 支持很多个 pointcut designators ,最常见的就是 execution 了。
matching method execution join points
匹配某一个特定方法:
@Pointcut("execution(public String info.einverne.FooDao.get(Long))")
假如要匹配 FooDao 中所有方法:
@Pointcut("execution(* info.einverne.FooDao.*(..))")
第一个*
匹配所有的返回值,(..)
表示匹配任意数量的参数。
limits matching to join points within certain types
使用 within 也能够达到上面的效果,将类型限定到 FooDao
@Pointcut("within(info.einverne.springboot.demo.dao.FooDao)")
public void logWithClass(JoinPoint jp) {}
或者匹配某个包下所有
@Pointcut("within(info.einverne.springboot.demo.dao..*)")
public void logWithPackage(JoinPoint jp) {}
this
匹配 bean reference 是给定类型的实例,target
匹配 target Object 是给定类型的实例。this
适用于 Spring AOP 创建 CGLIB-based proxy, target
适用于 JDK-based proxy.
@Pointcut("target(info.einverne.springboot.demo.dao.BaseDao)")
public void logBaseDao(JoinPoint jp) {}
@Pointcut("this(info.einverne.springboot.demo.dao.FooDao)")
public void logThis(JoinPoint jp) {}
limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types
匹配特定方法参数
// 匹配方法参数是 Long 的方法
@Pointcut("args(Long)")
public void argsMatchLong() {}
args 后面加类名,表示入参是该类的方法。
limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type
@Pointcut("@target(org.springframework.stereotype.Repository)")
limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given type(s)
// 匹配所有使用了 SomeCustomAnnotation 注解的参数的方法
@Pointcut("@args(info.einverne.SomeCustomAnnotation)")
public void args() {}
@args
需要接注解的类名,表示方法运行时入参标注了指定的注解。
limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP)
@Pointcut("@within(org.springframework.stereotype.Repository)")
等于:
@Pointcut("within(@org.springframework.stereotype.Repository *)")
@target
和 @within
的区别:Spring AOP 基于 dynamic proxies, 它仅仅提供了 public, non-static 方法执行的 interception. 而使用 CGLIB proxies, 你可以 intercept package-scoped, non-static 方法。然而 AspectJ 甚至可以 intercept 方法的调用(而不仅仅是方法的执行),member field access (静态或者非静态),constructor call/execution, static class initialisation 等等。2
@annotation
可以用来表示被注解引用的时机。
limits matching to join points where the subject of the join point (method being executed in Spring AOP) has the given annotation
比如自定义注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
}
那在定义 Pointcut 时可以使用:
@Around("@annotation(com.package.LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {}
可以使用 @Order
来指定先后执行顺序。
[[Spring @Order]]
execution 在使用时有自己的语法规则:
execution(modifiers-pattern? return-type-pattern declaring-type-pattern?method-name-pattern(param-pattern) throws-pattern?)
public/private void/String/... com.xxxx.SomeClass .saveUser throws *Exception
带问号的可以省略,其他可以支持正则。
所有的 Pointcut 之间都可以使用 &&
,||
, !
来连接。
@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {}
@Pointcut("within(com.xyz.someapp.trading..*)")
private void inTrading() {}
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {}
代码地址:https://github.com/einverne/thrift-swift-demo/tree/master/spring-boot-demo
wget https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
sudo chmod +x wp-cli.phar
sudo ln -s /var/www/www.einverne.info/html/wp-cli.phar /usr/local/bin/wp
wp --info
To run any command with WP CLI, you must be in the public directory of your WordPress instance installed.
Check version
wp core version
Check update
wp core check-update
Update
sudo -u www-data wp core update
sudo -u www-data wp core update-db
Check plugins
wp plugin list
sudo -u www-data wp plugin deactivate wordpress-seo
sudo -u www-data wp plugin uninstall wordpress-seo
sudo -u www-data wp plugin update --all
wp theme search twentyfourteen
sudo -u www-data wp theme install twentyfourteen
sudo -u www-data wp theme activate twentyfourteen
sudo -u www-data wp theme update twentyfourteen
sudo -u www-data wp theme update --all
wp theme list
sudo -u www-data wp theme activate twentyseventeen
sudo -u www-data wp theme uninstall twentyfourteen
wp post list
wp post create --post_type=post --post_title='A sample post'
wp post update 123 --post_status=draft
wp post delete 123
前两天鼻炎又犯了,去过很多次医院,也去过不同的医院,有说是慢性鼻炎,有说是过敏性鼻炎,这次检查说是鼻窦炎,总之就是鼻炎了。也尝试过各种药,各种滴鼻液,各种喷雾剂,各种洗鼻水,总是能缓解一段时间,然后到秋冬季节就又会差很多。也不知道是不是环境导致,毕竟大学毕业后还没有在不同城市生活过。所以上一次去了医院之后就在想,对于有些病,或者有些病理信息,是不是我可以在互联网上获得一些信息,然后自我调理,而这两天正好看到 Twitter 上有人提起,所以就整理一下。
专业的医学或健康知识可信获取信息源:
美国疾病控制与预防中心 https://www.cdc.gov/ 世界各国的 CDC https://en.wikipedia.org/wiki/CDC
美国国立卫生研究院 https://www.nih.gov/
糖尿病 https://dtc.ucsf.edu/zh-hans/
改造网站支持 Progressive Web Apps (PWA),改善移动端体验。
主要分成一下几步:
检测当前的浏览器是否支持 Service Worker
调试 Service Worker,可以在 Chrome 开发者选项 Application 看到 Service Worker.
创建 sw.js
并注册
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js');
//navigator.serviceWorker.ready always resolve
navigator.serviceWorker.ready.then(function (registration) {
console.log('Service worker successfully registered on scope', registration.scope);
});
});
}
</script>
关于 sw.js
比较复杂, 可以参考文末 Google 的文档。
manifest 属性
页面中添加 manifest.json 使之生效。
<link rel="manifest" href="/manifest.json">
这里 可以生成 manifest 和不同尺寸的 icon
部署后可以测试一下
整理文件的时候总想快速的删掉重复的文件,这里就总结下个人使用感觉良好的几个命令工具,包括 jdupes, rdfind, fdupes 这些。
依据推荐指数从高到低。
开源地址:
jdupes 是 fdupes 的增强版,根据作者自己的描述,jdupes 比 fdupes 1.51 版本要快 7 倍左右。
使用方式:
Usage: jdupes [options] DIRECTORY...
和 fdupes 类似, jdupes 也有类似的选项:
-d --delete prompt user for files to preserve and delete all
others; important: under particular circumstances,
data may be lost when using this option together
with -s or --symlinks, or when specifying a
particular directory more than once; refer to the
documentation for additional information
-N --noprompt together with --delete, preserve the first file in
each set of duplicates and delete the rest without
prompting the user
-r --recurse for every directory, process its subdirectories too
所以总结一下:
jdupes -r path/to/dir
这行命令不会真正去删重复的文件,如果要删除,用 -d
参数:
jdupes -dr path/to/dir
此时 jdupes 会打印出报告,然后一个一个让用户自己去确认要删除哪一个。
安装使用:
sudo apt-get install rdfind
rdfind -dryrun true path/to/dir
结果会保存在 results.txt 文件中。如果要真正删除 (Be Carefule):
rdfind -deleteduplicates true path/to/dir
或者建立硬链接
rdfind -makehardlinks true path/to/dir
安装使用:
sudo apt install fdupes
fdupes path/to/dir
递归搜索:
fdupes -r path/to/dir
如果要删除重复内容可以使用 -d
选项(同样需要非常谨慎):
fdupes -d path/to/dir
-d
选项会弹出选择,用户可以手动选择保留的文件。如果使用 -I
选项会在遇到重复文件时直接删除。
-N
选项和 --delete
一起使用时,会保留第一个文件,然后删除之后的重复文件,不会弹出让用户确认。
最强悍模式:
fdupes -rdN path/to/dir
在 review tldr 的 PR 时又看到了一个 C 语言实现的 duperemove,作者没有提供 benchmark,有机会可以尝试一下。
这篇文章受到 IntelliJ 官方插件 IDE Features Trainer 的启发,学习一个编辑器应该归类,从不同的操作学习。从基本的编辑,到代码导航,再到辅助,到重构,重要的不是学习这些快捷键,而是学习可以怎么样做,并且用这样的思考方式用到不同的编辑器中。
Mac 上常见的四个快捷键对应关系,简单的可以将 Alt 对应 Mac 下的 Option,而在 Mac 下 Cmd 和 Ctrl 被人为的分隔开来,Cmd 大多数与GUI相关,Cmd+Q退出应用,Cmd+W关闭一个Tab,而Ctrl和终端相关,Ctrl+a则是跳转到行首,Ctrl+e跳转到行尾。然后和Shift,Option结合就能组合成非常多常用的功能。Windows下不足的一个地方就是将 Win 键的功能单一化了,大部分的情况下Win 键是鸡肋。
另外 Shift 可以认为是一个相反的操作,比如 Cmd+Tab 是切换应用,那么 Cmd+Shift+Tab 就是反向切换应用。再比如在 IntelliJ IDEA 中 Cmd+z 是 undo,那么 Cmd+Shift+z 就是 redo,撤销之前的撤销。
一个编辑器基本的操作,包括复制,剪切,粘贴,选择,多点选择,折叠代码块等等。而关于复制,剪切,粘贴 IdeaVim 已经完全满足需求,不需要用 IntelliJ 内置的任何命令。
选择,块选择,本来 Vim 的选择模式也已经足够强大,不过 IntelliJ 提供了如下两个方式相较于 Vim 的块选稍微强大一些。
原来 Vim 的块选,比如想要选择某一个方法,大致可以使用 vap
,或者选择花括号内容 vi{
等等,在非常清楚需求的情况下非常方便,但是比如有些时候不想选择整个段落,想要可视化的选择一些代码块,不妨试试上面两个快捷键。
代码的折叠与展开,倒是不复杂。
多选,比较常见地一种场景就是变量重命名,当然有些时候比如编辑 html 时批量替换某些标签,有很多方法可以实现,比如变量重命名功能,或者批量替换,又或者使用 vim 的 dot 命令。
IntelliJ 当然也提供了很多方式,上面提到的只是其中的一种。
生成一些模板方法,默认的快捷键是 Cmd+n, 自动生成构造方法,toString 方法,get-set 方法,或者 override 方法等等。
批量重命名,很有用的快捷键,必须知道。
借助 IdeaVim 在我的配置文件中, 我把 ,+r
映射成了变量重命名:
nnoremap <Leader>r :<C-u>action RenameElement<CR>
Ctrl + Alt + V
个人对方法提取用的还是比较多的,重构代码或者重新规划代码时非常有用。
格式化,对于格式化的要求应该在任何保存的时候进行格式化,应该在提交代码前强制进行格式化。当然用快捷键时不时的格式化一下也可以。
显示参数
Vim 插件已经能够做到非常好的在单文件内浏览了,无论是上下,或者翻页,或者查询特定变量,方法。如果要做到查询方法的父类或者接口就不得不借助 IntelliJ 自身的快捷键。
我借助 IdeaVim 插件的魔力,将常见的代码流量都映射成了 g 开头的操作,比如跳转到超类就是 go to super, 快捷键就是 gs
在阅读代码时有几个操作经常会用到:
个人使用 Vim 的 *
和 np
基本满足了查询当前字符串的需求,所以这里也就不列举 IDE 自带的快捷键了。
全局搜索,默认的快捷键是 Shift + Shift, 这是一个非常有用的快捷键,可以搜索 IntelliJ IDEA 内部的功能,同时也可以模糊搜索项目代码文件,执行任务,跳转等等。
默认的快捷键是 Alt+Enter
默认的快捷键是 Alt(Option)+F12
重构代码,会弹出一个功能选单 Refactor this,在这个功能选单中可以做如下事情。
停留在变量上,方法名,类名上:
Cmd 系列
快捷键 | 功能描述 |
---|---|
Cmd+q | Q退出应用 |
Cmd+c/v/x | copy/paste/cut |
Cmd+z | |
Cmd+w | close Tab |
Cmd+e | recent file |
Cmd+n | generate |
Cmd+o | file structure |
Ctrl 系列
快捷键 | 功能描述 |
---|---|
Ctrl+a/e | 行首行尾 |
Ctrl+n/p | next line/Previous line |
Ctrl+b | go to super class |
Ctrl+g | find usage |
Ctrl+h | find in path |
Ctrl+Option+b | go to implements |
Linux Mint 自带的备份和还原工具就是 timeshift, 今天看到有人贡献 timeshift 的命令行版本,突然意识到这个工具其实还有命令行版本。
sudo apt-add-repository -y ppa:teejee2008/ppa
sudo apt-get update
sudo apt-get install timeshift
timeshift 提供两种模式的备份方式:
RSYNC 在第一次使用时会拷贝所有文件,以后每次备份都是增量备份,使用硬链接创建从上一次快照未修改的系统文件。快照文件可以保存到任何 Linux 文件系统的硬盘格式下,保存快照到非系统盘或者外部硬盘上,这样即使系统盘损坏或者被格式化也能够快速从外部硬盘恢复数据。RSYNC 支持排除文件和目录来节省硬盘空间。
BTRFS 需要安装 btrfs-tools
,快照通过 BTRFS 文件系统创建,快照备份和恢复的速度要比 RSYNC 快,快照创建和恢复都是原子事务的,不能中断。快照通过替换系统 subvolumns 来恢复,因为文件没有拷贝,删除或者覆盖,不会有文件丢失的风险。恢复后的系统会作为一次新的快照。快照在备份时是完美地逐字节拷贝,不能排除任何文件。快照会存在系统相同的硬盘上,暂时还不支持备份到其他硬盘,如果系统盘损坏,那么快照也会丢失。初始 BTRFS 备份是 0 字节,但是随着系统使用占用内容会逐日增多,快照中的文件依然还是会指向原始的文件 block. 系统必须安装在 BTRFS 分区上,并使用 Ubuntu-type subvolumn layout(@ and @home subvolumns),其他的 layouts 不支持。
通过界面可以非常快速的设置 timeshift.
在标签页,Filters 一栏中可以设置不备份的路径。
通过界面可以定制简单的定时备份任务,但是如果界面无法满足高级的需求,比如固定时间调用 timeshift 来备份,那么可以使用 cron 脚本来定时备份。比如要在每天下午 7 点中执行备份,可以新建 /etc/cron.d/timeshift_daily_7p
并在其中配置:
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=""
0 19 * * * root timeshift --create --tags D --scripted
如果安装某些程序导致了无法进入系统,那么可以用 USB 上的系统进入,然后在 USB 启动的系统中使用 timeshift 来恢复系统。
优化 Docker 镜像文件的大小可以:
Docker 镜像由很多层组成(最多 127 层),依赖很多底层基础,比如文件系统,写时复制,联合挂载等等,每创建一层都会相应地增加一些体积。
使用 Alpine 作为基础镜像。
gcr.io/google_containers/pause-amd64:3.1
镜像仅有 742KB。
scratch 是一个空镜像,只能用于构建其他镜像,比如你要运行一个包含所有依赖的二进制文件,如 Golang 程序,可以直接使用 scratch 作为基础镜像。Google pause 镜像 Dockerfile:
FROM scratch
ARG ARCH
ADD bin/pause-${ARCH} /pause
ENTRYPOINT ["/pause"]
Google pause 镜像使用了 scratch 作为基础镜像,这个镜像本身是不占空间的,使用它构建的镜像大小几乎和二进制文件本身一样大,所以镜像非常小。当然在我们的 Golang 程序中也会使用。对于一些 Golang/C 程序,可能会依赖一些动态库,你可以使用自动提取动态库工具,比如 ldd、linuxdeployqt 等提取所有动态库,然后将二进制文件和依赖动态库一起打包到镜像中。
scratch 是个空镜像,如果希望镜像里可以包含一些常用的 Linux 工具,busybox 镜像是个不错选择,镜像本身只有 1.16M,非常便于构建小镜像。
减少 RUN 指令
应该把多个命令串联合并为一个 RUN(通过运算符 && 和 / 来实现),每一个 RUN 要精心设计,确保安装构建最后进行清理,这样才可以降低镜像体积,以及最大化的利用构建缓存。
下面是一个优化前 Dockerfile
:
FROM ubuntu
ENV VER 3.0.0
ENV TARBALL http://download.redis.io/releases/redis-$VER.tar.gz
# ==> Install curl and helper tools...
RUN apt-get update
RUN apt-get install -y curl make gcc
# ==> Download, compile, and install...
RUN curl -L $TARBALL | tar zxv
WORKDIR redis-$VER
RUN make
RUN make install
# ==> Clean up
WORKDIR /
RUN apt-get remove -y --auto-remove curl make gcc
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/* /redis-$VER
CMD ["redis-server"]
构建镜像,名称叫 test/test:0.1。
我们对 Dockerfile
做优化,优化后 Dockerfile
:
FROM ubuntu
ENV VER 3.0.0
ENV TARBALL http://download.redis.io/releases/redis-$VER.tar.gz
RUN echo "==> Install curl and helper tools..." && \
apt-get update && \
apt-get install -y curl make gcc && \
echo "==> Download, compile, and install..." && \
curl -L $TARBALL | tar zxv && \
cd redis-$VER && \
make && \
make install && \
echo "==> Clean up..." && \
apt-get remove -y --auto-remove curl make gcc && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /redis-$VER
CMD ["redis-server"]
构建镜像,名称叫 test/test:0.2。
对比两个镜像大小:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test/test 0.2 58468c0222ed 2 minutes ago 98.1MB
test/test 0.1 e496cf7243f2 6 minutes ago 307MB
将多条 RUN 命令串联起来构建的镜像大小是每条命令分别 RUN 的三分之一。
为了应对镜像中存在太多镜像层,Docker 1.13 版本以后,提供了一个压扁镜像功能,即将 Dockerfile
中所有的操作压缩为一层。这个特性还处于实验阶段,Docker 默认没有开启,如果要开启,需要在启动 Docker 时添加 -experimental
选项,并在 Docker build 构建镜像时候添加 --squash
。不推荐使用这个办法,请在编写 Dockerfile
时遵循最佳实践编写,不要试图用这种办法去压缩镜像。
在了解复式计帐开源软件 Beancount 的时候偶然的知道了 git-crypt, 因为 beancount 使用纯文本来记账,非常适合使用 git 来做管理,而个人帐务资产信息又是非常敏感的内容,所以就有了 git-crypt 的使用场景。而在日常的项目管理中,如果遇到代码需要公开,而某些敏感配置,比如数据库连接配置等等,使用相同的原理 git-crypt 也能够有使用场景。
git-crypt 使用 C++ 编写,安装的过程可以自行编译安装:
git clone git@github.com:AGWA/git-crypt.git
sudo apt install make g++ libssl-dev git openssl
sudo make ENABLE_MAN=yes install
详细参考官网,安装后会在 /usr/local/bin
目录中,可以使用 man git-crypt
来查看说明。
而对于 MacOS, 只需要安装 git-crypt
,gpg
即可:
brew install gpg
brew install git-crypt
在 git 项目中加密敏感内容
配置加密工具 gpg
# gpg --gen-key // 生成密钥(公钥和私钥),按照流程提示进行
# gpg --list-keys // 列出当前所有的密钥,检查刚才的密钥是否生成成功
配置 git-crypt
cd path/to/project
git-crypt init // 类似于 git init,安装 git-crypt 到项目中
git-crypt add-gpg-user einverne // 添加密钥用户,这里以我的用户 einverne 为例
添加配置文件 .gitattributes
vi .gitattributes
格式为: * filter=git-crypt diff=git-crypt , 例如我要加密 config 文件夹的三个配置文件 , 则在 .gitattributes
文件内加入:
secretfile filter=git-crypt diff=git-crypt
*.key filter=git-crypt diff=git-crypt
secretdir/** filter=git-crypt diff=git-crypt
上传到 git
# git rm -r --cached config/ // 清理 config 的 git 缓存
# git add .
# git commit -m 'git-crypt'
# git push
导出密钥
# git-crypt export-key ~/Desktop/git-crypt-key
导出了密钥以后,就可以分发给有需要的团队内部人员。
当团队其他成员获取了代码以后,需要修改配置文件,需要先解密,解密动作只需要做一次,往后就不需要再进行解密了。
解密
# git-crypt unlock /path/to/git-crypt-key
利用该方式进行配置文件管理可以保证安全性,只有团队内相关人员才能看到配置文件明文内容,解密只需要第一次进行,之后就没什么改变,直接改配置文件,git 提交会自动加密。