0


我是如何使用 Git 和服务器做图床,并使用 hook 实现 WebP 压缩与水印的?

通常,我们的网站存储空间、网络受限,会将图片和网站分开进行存储和“解耦”,方便后续使用 CDN 加速时,图片和网站可以分开使用不同方案;也方便网站迁移时,只迁移网站本体。

不知道有没有小伙伴想过: 在自己的腾讯云轻量应用服务器上,部署 Git 服务端作为图床仓库,重新定向工作空间到网站目录,并使用 Git hook 实现图片的 WebP 压缩与水印? 这次就给大家浅浅分享一下。

Git

Git 相信大家都不陌生,它是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。Git 由 Linux 之父 Linus 于 2005 年创建,目前由 Git 软件基金会管理。

Git 的核心思想是分布式,推送内容使用 Hash 进行差异化校验,使得 Git 具有更高的可靠性和更快的速度。Git 还支持离线工作,这意味着你可以在没有网络连接的情况下进行开发,然后将其推送到远程仓库。也正是这个特性,使得 Git 成为了一个非常流行的版本控制系统。而我们,也可以使用这些特性,来创建一个图床。
舒服

想一想,本地存储图片,之后使用 Git 推送到远程仓库,是不是很方便呢?

如果是写文章,对于一些草稿图片,甚至还可以使用 Git 拉出分支,在文章完成后,合并主分支,统一上线。保持工作台干净,岂不美哉?

#mermaid-svg-rlaET8uHjfjzUToV {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-rlaET8uHjfjzUToV .error-icon{fill:#552222;}#mermaid-svg-rlaET8uHjfjzUToV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rlaET8uHjfjzUToV .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-rlaET8uHjfjzUToV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rlaET8uHjfjzUToV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rlaET8uHjfjzUToV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rlaET8uHjfjzUToV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rlaET8uHjfjzUToV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rlaET8uHjfjzUToV .marker.cross{stroke:#333333;}#mermaid-svg-rlaET8uHjfjzUToV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rlaET8uHjfjzUToV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rlaET8uHjfjzUToV .cluster-label text{fill:#333;}#mermaid-svg-rlaET8uHjfjzUToV .cluster-label span{color:#333;}#mermaid-svg-rlaET8uHjfjzUToV .label text,#mermaid-svg-rlaET8uHjfjzUToV span{fill:#333;color:#333;}#mermaid-svg-rlaET8uHjfjzUToV .node rect,#mermaid-svg-rlaET8uHjfjzUToV .node circle,#mermaid-svg-rlaET8uHjfjzUToV .node ellipse,#mermaid-svg-rlaET8uHjfjzUToV .node polygon,#mermaid-svg-rlaET8uHjfjzUToV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rlaET8uHjfjzUToV .node .label{text-align:center;}#mermaid-svg-rlaET8uHjfjzUToV .node.clickable{cursor:pointer;}#mermaid-svg-rlaET8uHjfjzUToV .arrowheadPath{fill:#333333;}#mermaid-svg-rlaET8uHjfjzUToV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rlaET8uHjfjzUToV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rlaET8uHjfjzUToV .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-rlaET8uHjfjzUToV .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-rlaET8uHjfjzUToV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rlaET8uHjfjzUToV .cluster text{fill:#333;}#mermaid-svg-rlaET8uHjfjzUToV .cluster span{color:#333;}#mermaid-svg-rlaET8uHjfjzUToV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rlaET8uHjfjzUToV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

  1. 开始
  2. 本地存储图片/拉取 Git 仓库
  3. 是否为草稿图片
  4. 创建 Git 分支
  5. 推送到远程仓库
  6. 合并主分支
  7. 发布图片

Bare 裸仓库

平时,我们使用 Git 时,一般会使用工作区,也就是我们平时写代码的地方。
工作区和版本控制区

进入

  1. .git

目录,就可以看到版本控制区:
Git 仓库

但是,我们在服务器上部署的 Git 仓库,不需要工作空间,只需要版本库,用于提供给客户端进行拉取和推送。所以,在服务器上,我们就可以使用裸仓库,作为图床仓库:

  1. # 创建一个裸仓库git init --bare

裸仓库

hook 钩子

Git 提供了钩子机制,允许我们在 Git 仓库中添加自定义脚本,以在特定事件发生时执行。这些事件包括:提交、推送、合并、拉取等。钩子脚本可以在仓库的

  1. .git/hooks

目录中找到。

我们可以使用这些钩子脚本,来执行一些自定义操作,比如: 重新定向工作空间,以及后续的图片压缩、水印等操作。

裸仓库同样提供了 hook 钩子。比如,我们可以在

  1. hooks/post-receive

中,编写脚本,实现重新定向工作空间:

  1. #!/bin/zsh# 重新定向工作空间,pathToWebSite 为网站目录,pathToBarePath 为裸仓库目录git --work-tree=/pathToWebSite --git-dir=/pathToBarePath checkout -f

这样,本地推送图片到服务器上的 Git 裸仓库的流程就是:

#mermaid-svg-V8dvuPHXDCOmwqxm {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-V8dvuPHXDCOmwqxm .error-icon{fill:#552222;}#mermaid-svg-V8dvuPHXDCOmwqxm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-V8dvuPHXDCOmwqxm .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-V8dvuPHXDCOmwqxm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-V8dvuPHXDCOmwqxm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-V8dvuPHXDCOmwqxm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-V8dvuPHXDCOmwqxm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-V8dvuPHXDCOmwqxm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-V8dvuPHXDCOmwqxm .marker.cross{stroke:#333333;}#mermaid-svg-V8dvuPHXDCOmwqxm svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-V8dvuPHXDCOmwqxm .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-V8dvuPHXDCOmwqxm text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-V8dvuPHXDCOmwqxm .actor-line{stroke:grey;}#mermaid-svg-V8dvuPHXDCOmwqxm .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-V8dvuPHXDCOmwqxm .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-V8dvuPHXDCOmwqxm #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-V8dvuPHXDCOmwqxm .sequenceNumber{fill:white;}#mermaid-svg-V8dvuPHXDCOmwqxm #sequencenumber{fill:#333;}#mermaid-svg-V8dvuPHXDCOmwqxm #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-V8dvuPHXDCOmwqxm .messageText{fill:#333;stroke:#333;}#mermaid-svg-V8dvuPHXDCOmwqxm .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-V8dvuPHXDCOmwqxm .labelText,#mermaid-svg-V8dvuPHXDCOmwqxm .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-V8dvuPHXDCOmwqxm .loopText,#mermaid-svg-V8dvuPHXDCOmwqxm .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-V8dvuPHXDCOmwqxm .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-V8dvuPHXDCOmwqxm .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-V8dvuPHXDCOmwqxm .noteText,#mermaid-svg-V8dvuPHXDCOmwqxm .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-V8dvuPHXDCOmwqxm .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-V8dvuPHXDCOmwqxm .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-V8dvuPHXDCOmwqxm .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-V8dvuPHXDCOmwqxm .actorPopupMenu{position:absolute;}#mermaid-svg-V8dvuPHXDCOmwqxm .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-V8dvuPHXDCOmwqxm .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-V8dvuPHXDCOmwqxm .actor-man circle,#mermaid-svg-V8dvuPHXDCOmwqxm line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-V8dvuPHXDCOmwqxm :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
本地计算机

  1. 腾讯云轻量应用服务器
  2. Git 裸仓库
  3. 网站目录(Nginx)
  4. 推送图片到 Git 裸仓库
  5. 接收推送
  6. 触发 post-receive 钩子
  7. 更新网站目录
  8. 本地计算机
  9. 腾讯云轻量应用服务器
  10. Git 裸仓库
  11. 网站目录(Nginx)

既然 hook 是 shell 脚本,那么我们就可以使用 shell 脚本来实现图片的 WebP 压缩与水印了。

其实方法很多,比如:

  1. imagemagick

,它是一个功能强大的图片处理工具,支持多种图片格式的转换,以及图片的裁剪、缩放、旋转、水印、滤镜等操作。
嘿嘿,看个人习惯啦

但是我更习惯用 python 的

  1. Pillow

库,同样,它是一个强大的图像处理库,支持多种图片格式的转换。

WebP 格式

WebP 既支持有损压缩也支持无损压缩,相较于 PNG 格式,同样支持透明通道。在质量相同的情况下,WebP 也具有更小的文件体积。
WebP

所以,使用 WebP 格式,可以节省很间,进而提高网站内图片的加载速度; WebP 格式也支持渐进式加载,还可以进一步提高用户体验。

操作前提

本文的操作前提,是什么呢?首先是要有一台 Linux 服务器,比如:我就是使用腾讯云的轻量应用服务器。

其实也可以买 腾讯云的云服务器 (CVM) 选配更强大的 CPU ,处理 WebP 压缩速度更快。

但是,我测试了一下,我使用的腾讯云轻量应用服务器,CPU 模拟型号是 Intel® Xeon® Gold 6133 CPU @ 2.50GHz,处理本文的 WebP 并行任务非常足够。
本次使用的演示服务器

软件方面,在腾讯云轻量应用服务器上,安装好 Git 和 Python:

  1. # 安装 Gitapt update &&aptinstallgit -y
  2. # 安装 Pythonaptinstall python3 python3-pip -y

与此同时,创建一个 Git 裸仓库,作为图床仓库:

  1. # 创建一个裸仓库git init imageHost.git --bare

创建图床仓库

图片转 WebP

如何将图片转成 WebP 格式呢? 前文已经说到,使用 Pillow 库。

Pillow 库支持多种图片格式的转换,包括:

  1. JPEG

  1. PNG

  1. GIF

  1. BMP

  1. TIFF

  1. PPM

  1. WebP

等。

按道理我们在腾讯云轻量应用服务器使用的是 Linux 镜像,是可以安装 Linux 的 imagemagick 库的。感兴趣的小伙伴可以尝试一下。

当然,其实你也可以使用存储桶的 WebP 转换功能,比如:腾讯云的 COS 存储桶。
腾讯云 COS WebP 转换

其实我也有用过(大概 2021 年的时候?),改天有机会,给大家介绍一下。

Pillow 库

我们可以很方便地实现图片的 WebP 转换:

  1. from PIL import Image
  2. defsave_as_webp(image_target, target_path):"""
  3. 将图像保存为 WebP 格式,并进行优化设置.
  4. Args:
  5. image_target (PIL.Image.Image): 待保存的图像对象.
  6. target_path (str): 保存图像的目标路径.
  7. """# 保存图像文件为 WebP 格式# quality: 图像质量,范围0-100,越高质量越好,但文件越大# optimize: 启用无损优化,减小文件大小# lossless: 启用无损压缩,保证图像质量# method: 压缩方法,取值0-6,越大压缩比越大,但质量略有下降# save_all: 保存动画的所有帧# progressive: 启用渐进式显示
  8. image_target.save(target_path,'webp', quality=80, optimize=True, lossless=False, method=6,
  9. save_all=True,
  10. progressive=True)if __name__ =="__main__":# 假设图像对象为 image_obj
  11. image_obj = Image.open("path/to/image.jpg")# 定义保存路径
  12. target_path ="path/to/save/image.webp"# 保存为 WebP 格式
  13. save_as_webp(image_obj, target_path)

添加水印

Pillow 库同样支持添加水印,只需要把水印图片“贴”到目标图片上即可:

  1. from PIL import Image, ImageDraw, ImageFont
  2. defadd_watermark(input_path, watermark_path, output_path):"""
  3. 在图像上添加水印.
  4. Args:
  5. input_path (str): 原始图像的路径.
  6. watermark_path (str): 水印图像的路径.
  7. output_path (str): 添加水印后的图像保存路径.
  8. """# 打开原始图像
  9. image = Image.open(input_path)# 打开水印图像
  10. watermark = Image.open(watermark_path)# 获取原始图像和水印图像的尺寸
  11. image_width, image_height = image.size
  12. watermark_width, watermark_height = watermark.size
  13. # 计算水印的位置,置于右下角
  14. x = image_width - watermark_width -20
  15. y = image_height - watermark_height -20# 将水印图像叠加到原始图像上
  16. image.paste(watermark,(x, y), watermark)# 保存结果图像
  17. image.save(output_path)# 示例用法
  18. add_watermark("path/to/image.jpg","path/to/watermark.png","path/to/output.jpg")

一般,水印的位置在图片的下方,并且水印需要设置透明度,在图片的尺寸过小时候,取消水印:

  1. with Image.open(input_path)as image:
  2. original_size = os.path.getsize(input_path)# 计算水印的放置位置以底部居中
  3. bg_width, bg_height = image.size
  4. wm_width, wm_height = wm_img.size
  5. position =((bg_width - wm_width)//2, bg_height - wm_height -30)# 底部居中坐标# 创建一个新的透明图层用于合并,以防背景颜色受影响
  6. image_target = Image.new('RGBA', image.size,(255,255,255,0))# 完全透明图层
  7. image_target.paste(image,(0,0))# 将背景图片粘贴到透明图层上# 粘贴水印到新图层的底部中心位置,透明度已由水印图片自身定义,无需额外调整if bg_width >512*1.5and watermark_mode:
  8. image_target.paste(wm_img, position, mask=wm_img.split()[3])# 使用alpha通道作为遮罩确保透明度正确

最终的流程就是:

#mermaid-svg-IlwmP2dgVoPTE5M3 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-IlwmP2dgVoPTE5M3 .error-icon{fill:#552222;}#mermaid-svg-IlwmP2dgVoPTE5M3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-IlwmP2dgVoPTE5M3 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-IlwmP2dgVoPTE5M3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-IlwmP2dgVoPTE5M3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-IlwmP2dgVoPTE5M3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-IlwmP2dgVoPTE5M3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-IlwmP2dgVoPTE5M3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-IlwmP2dgVoPTE5M3 .marker.cross{stroke:#333333;}#mermaid-svg-IlwmP2dgVoPTE5M3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-IlwmP2dgVoPTE5M3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-IlwmP2dgVoPTE5M3 .cluster-label text{fill:#333;}#mermaid-svg-IlwmP2dgVoPTE5M3 .cluster-label span{color:#333;}#mermaid-svg-IlwmP2dgVoPTE5M3 .label text,#mermaid-svg-IlwmP2dgVoPTE5M3 span{fill:#333;color:#333;}#mermaid-svg-IlwmP2dgVoPTE5M3 .node rect,#mermaid-svg-IlwmP2dgVoPTE5M3 .node circle,#mermaid-svg-IlwmP2dgVoPTE5M3 .node ellipse,#mermaid-svg-IlwmP2dgVoPTE5M3 .node polygon,#mermaid-svg-IlwmP2dgVoPTE5M3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-IlwmP2dgVoPTE5M3 .node .label{text-align:center;}#mermaid-svg-IlwmP2dgVoPTE5M3 .node.clickable{cursor:pointer;}#mermaid-svg-IlwmP2dgVoPTE5M3 .arrowheadPath{fill:#333333;}#mermaid-svg-IlwmP2dgVoPTE5M3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-IlwmP2dgVoPTE5M3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-IlwmP2dgVoPTE5M3 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-IlwmP2dgVoPTE5M3 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-IlwmP2dgVoPTE5M3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-IlwmP2dgVoPTE5M3 .cluster text{fill:#333;}#mermaid-svg-IlwmP2dgVoPTE5M3 .cluster span{color:#333;}#mermaid-svg-IlwmP2dgVoPTE5M3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-IlwmP2dgVoPTE5M3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

  1. 开始
  2. 读取原始图像
  3. 图像尺寸 >= 512 * 1.5?
  4. 添加水印
  5. 跳过添加水印
  6. 保存为WebP格式
  7. 结束

文章内的图片,就是这样转换的。

Git 差异化文件

Git 作为版本控制工具,可以很方便地实现差异化文件检录,可能平时大家用习惯了 JetBrains、GitHub Desktop 等工具,但是,Git 的命令行强大到可怕。

我们如果要实现两个 commit 的差异化文件,只需要使用

  1. git diff

命令即可:

  1. # 比较两个 commit 的差异gitdiff<commit-id><commit-id>

比如:比较 Hash 值为

  1. 6abbb89127c806928666b12374dfa013ef95f8b8

和 Hash 值为

  1. 5fe2590034f4922c427ab74bf948af46c2627d99

的两个 commit 的差异:
git diff

是不是有点抽象? 这里我们可以使用类似的命令

  1. git difftree

并追加一下参数:

  • --no-commit-id:输出的差异信息中不包含提交 ID;
  • --name-status:仅显示文件名和状态(如添加、修改、删除等),而不显示具体的差异内容;
  • -r:递归地比较两个树中的所有子树。

这样的结果就豁然开朗了:
git diff-tree

这个时候,如果两次 commit 存在差异,那么可能的输出结果就是:

  1. # 修改文件
  2. M modified_file.png
  3. # 添加文件
  4. A new_file.png
  5. # 删除文件
  6. D deleted_file.jpg
  7. # 重命名文件、移动文件
  8. R old_name.png new_name.pg

发现了什么?🤔 没错,我们在 shell 内,可以使用标准化输出的方式,格式化参数文件。
很丝滑

hook 实现

现在,我们看看如何使用 hook 实现自动化部署。首先是工作分区的重定向和参数的定义:

  1. # 定义图片文件后缀(需要转换为 WebP 格式的文件后缀)image_extensions=(".png"".jpg"".jpeg"".PNG")# 网站目标目录WEB_DIR="/www/webRoot/imagehost.mintimate.cn"# 工作空间临时检录目录WORK_SPACE_DIR="/home/git/mySpace/imagehost.mintimate.cn"# 定义需要跳过的文件前缀skip_prefixes=("emoticon""emoji")# Python Fle PathPYTHON_MAIN="/home/git/PythonTool"# 检录工作空间到目标目录git --work-tree=$WORK_SPACE_DIR --git-dir=/home/git/mySource/imageHost.git checkout -f

因为,我们提交内容的时候,难免会提交一些无关紧要的文件,比如:表情包、emoji 等,所以,我们需要过滤掉这些文件,并定义需要转换的文件后缀以及需要跳过的文件前缀,配合函数完成逻辑判断:

  1. # 定义一个函数,用于检查文件路径是否以需要跳过的前缀开头check_skip_prefix(){localfilepath=$1forprefixin"${skip_prefixes[@]}";doif[["$filepath"=="$prefix"* ]];thenreturn0# 返回 0 表示匹配到了需要跳过的前缀fidonereturn1# 返回 1 表示没有匹配到需要跳过的前缀}# 定义一个函数,用于检查文件是否为图片is_image_file(){localfilepath=$1forextin"${image_extensions[@]}";doif[["$filepath"== *"$ext"]];thenreturn0# 返回 0 表示是图片文件fidonereturn1# 返回 1 表示不是图片文件}

定义日志输出目录:

  1. # 定义输出目录OUTPUT_DIR="/home/git/runLog"# 确保输出目录存在mkdir -p $OUTPUT_DIR# 获取当前日期和时间,格式为 YYYYMMDD-HHMMSSNOW=$(date +"%Y%m%d-%H%M%S")# 定义输出文件,包含时间戳OUTPUT_FILE="${OUTPUT_DIR}/${NOW}_Change.log"

之后,标准化我们上文使用

  1. git difftree

命令的输出:

  1. # 读取标准输入(oldrev newrev refname)whileread oldrev newrev refname
  2. do# 获取变更的文件列表echo"Changes in $refname:">>$OUTPUT_FILE# 使用 git diff-tree 来查看变更git diff-tree --no-commit-id --name-status -r $oldrev$newrev|whileread status_flag file1 file2
  3. docase$status_flagin
  4. M|A)echo"Modify: $file1">>$OUTPUT_FILE;;
  5. D)echo"Delete: $file1">>$OUTPUT_FILE;;
  6. R)echo"MV $file1 To $file2">>$OUTPUT_FILE;;esacdonedone

最后,对文件进行二次读取,判断是否需要使用 Python 脚本进行转换:

  1. # 使用 case 语句处理不同的操作whileread line;docase$linein
  2. Modify*)filepath=$(echo $line |awk'{print $2}')
  3. process_file "$filepath" modify
  4. ;;
  5. Delete*)filepath=$(echo $line |awk'{print $2}')rm -f "$WEB_DIR/$filepath"rm -f "$WEB_DIR/${filepath%.*}.webp";;
  6. MV*)src=$(echo $line |awk'{print $2}')dst=$(echo $line |awk'{print $3}')rm -f "$WEB_DIR/$src"rm -f "$WEB_DIR/${src%.*}.webp"
  7. process_file "$dst" move
  8. ;;esacdone<$OUTPUT_FILE

当然,

  1. process_file

函数的实现就比较简单了,直接调用 Python 脚本即可:

  1. # 使用 Python WebP解析脚本process_file(){localfilepath=$1localaction=$2# 判断是否存在上级目标目录mkdir -p "$(dirname"$WEB_DIR/$filepath")"# 检查文件路径是否以需要跳过的前缀开头
  2. check_skip_prefix "$filepath"if[$? -eq 0];thencp"$WORK_SPACE_DIR/$filepath""$WEB_DIR/$filepath"returnfi# 检查文件是否为图片
  3. is_image_file "$filepath"if[$? -eq 0];then# 执行 python 脚本nohup$PYTHON_MAIN/bin/python $PYTHON_MAIN/image2WebpForGit.py -w -s "$WORK_SPACE_DIR/$filepath" -t "$WEB_DIR/${filepath%.*}.webp">>$OUTPUT_FILE_PY2>&1&else# 如果不是图片,执行 cp 命令cp"$WORK_SPACE_DIR/$filepath""$WEB_DIR/$filepath"fi}

需要注意,这里我预留了

  1. action

参数,但是我没有使用。

最终效果

最后,我们来看看效果,经过 commit 和 push 操作推送到我们自己的 Git 仓库之后,进而存储到腾讯云轻量应用服务器 Linux 的硬盘存储内,可以查看日志:
查看 Git Hook 操作日志

与此同时,我们也可以在

  1. web

目录下查看转换后的图片:
查看 Git Hook 转换后的图片
看看转换后的图片和原始图片的大小对比:
查看 Git Hook 转换后的图片大小

同时,本篇文章内的图片,也是使用上述方法转换的,

对于性能的消耗,也是微乎其微的,我们可以在腾讯云轻量应用服务器的后台,看到性能监控曲线:
腾讯云轻量应用服务器性能监控曲线

END

好啦,本篇文章就到这里,感谢阅读。之后的步骤,就看每个人的想法了。比如我就是使用 Nginx 作为反向代理,将转换后的图片直接返回给用户,这样就可以减少服务器的负担了。

有时候也会套一层 CDN,这样就可以加速图片的访问了。

相关代码已经开源,可以访问 https://github.com/Mintimate/GitHookPng2WebP 查看。

最后,制作教程不易,寻找教程也不易,找到志同道合的小伙伴更是知音难觅。如果你对云服务器、CDN、云数据库和Linux等云计算感兴趣,亦或者喜欢编程、设计、产品、运营等领域,欢迎加入我们的开发者爱好群,一起交流学习: 812198734 (目前可能就我一个人?毕竟才刚刚创建 ~)。

标签: git 服务器 devops

本文转载自: https://blog.csdn.net/weixin_43890033/article/details/143862846
版权归原作者 Mintimate 所有, 如有侵权,请联系我们删除。

“我是如何使用 Git 和服务器做图床,并使用 hook 实现 WebP 压缩与水印的?”的评论:

还没有评论