☰
git-ftp 版本演进全解析:从增量 FTP 部署到多协议同步的完整技术图谱
2026/10/12 2:02:05 网站建设 项目流程
  • 开发工具
  • CLI
  • DevOps

【免费下载链接】git-ftp

Uses Git to upload only changed files to FTP servers.

项目地址:https://gitcode.com/gh_mirrors/gi/git-ftp
点击查看免费下载

导读:本文以 git-ftp 官方 CHANGELOG.md 为主线,系统梳理该项目从 0.7.3 到 1.6.0-UNRELEASED 的每一个重要版本变更,并结合仓库内的主脚本 git-ftp、手册 man/git-ftp.1.md 与测试 tests/git-ftp-test.sh 的源码级实现逐一印证。读完本文,你将理解 git-ftp 的部署状态跟踪原理、子模块处理、钩子系统、Scope 作用域、LFTP 下载/拉取等核心机制的来龙去脉,以及每个版本特性对应的真实代码位置。

一、git-ftp 的核心原理与版本演进的底层主线

在展开版本叙事之前,有必要先明确 git-ftp 的工作基石,因为 CHANGELOG 中几乎所有变更都围绕这三条主线展开:

  1. 增量上传:git-ftp 是一个"Git 驱动的 FTP 客户端",它借助git diff判断自上次部署以来本地哪些文件发生了变化,只上传这些文件,从而节省带宽与时间(见 README.md 开篇说明)。
  2. 远程状态跟踪:git-ftp 将"最后一次部署的提交 SHA1"写入服务器上的.git-ftp.log文件(默认文件名,可用deployedsha1file配置覆盖),远程主机上无需安装 Git。set_deployed_sha1_file()与upload_local_sha1()分别对应读取与写入逻辑(git-ftp、git-ftp)。
  3. 双引擎架构:上传、删除、日志读取等"push 侧"操作由 curl 完成;而download、pull、snapshot等"pull 侧"实验性功能依赖 lftp 的 mirror 命令。这一架构决定了 CHANGELOG 中大量条目(如 1.5.1 的--proxy、1.6.0 的 FTPES/--insecure支持)会分别作用于 curl 与 lftp 两条路径。

版本时间线总览

版本主题关键能力
1.6.0-UNRELEASED稳定性打磨退出码调整、SFTP 目录创建修复、子模块/嵌套 scope 支持、布尔配置、FTPES 拉取
1.5.2配置与文档core.hooksPath、Windows 安装文档、日志文件名修复
1.5.1连接能力FTPES 修复、--proxy、--insecure从 git config 读取
1.5.0过滤与钩子ignore 文件改为 glob、post hook 引用部署 SHA1、curl 存在性检查
1.4.0密钥与文档--key/--pubkey解耦、--cacert安全处理、未知远程提交失败
1.3.x初始化与平台--auto-init、busyboxmktmp兼容
1.3.0钩子与快照pre/post-ftp-push钩子、--changed-only、snapshot动作、vsftpd 测试环境
1.2.0双向同步pull、download(lftp)、--diff-filter、文件名编码
1.1.0缓冲与过滤上传/删除缓冲、glob 过滤、-P交互式密码、临时目录
1.0.x稳定性远程访问预检、删除缓冲防 ARG_MAX、--remote-root、子模块 catchup
0.9.0日志查看log动作、密码引用修复
0.8.x连接与安全--scope无参取分支名、--insecure/--cacert、单连接 5x 提速
0.7.x作用域与过滤add-scope/remove-scope、ignore 文件注释支持

二、1.6.0-UNRELEASED:未发布版本中的稳定性与体验打磨

这是 CHANGELOG 中记录的最后一个版本(对应手册 man/git-ftp.1.md 标注的 1.6.0),虽然标记为 UNRELEASED,但其变更最能体现项目维护者对工程细节的打磨方向。

1. 退出码语义修正:远程不可达从 5 改为 4

原文档要点:Change exit code when remote cannot be accessed from 5 (ERROR_DOWNLOAD) to 4 (ERROR_UPLOAD)

远程不可访问本质上是"上传侧的失败",此前却错误地返回"下载错误"码 5。修正后在check_remote_access()中,无论 curl 探测远程路径失败,还是 SFTP 下自动MKDIR创建目录失败,最终都以ERROR_UPLOAD(4)结束(git-ftp)。这与脚本顶部定义的常量ERROR_UPLOAD=4、ERROR_DOWNLOAD=5(git-ftp)严格对应。

2. SFTP 目录创建修复

check_remote_access()中有一段针对 SFTP 的专门逻辑:当 curl 访问远程路径返回错误码 78(资源不存在)且协议为sftp时,自动追加-Q "MKDIR $REMOTE_PATH"指令创建远程目录(git-ftp)。这正是 CHANGELOG 所记"Fix directory creation with SFTP"的实现位置。

3. 子模块处理与嵌套分支名

  • 子模块修复:handle_submodule_sync()在子模块 push 失败(返回ERROR_DOWNLOAD即 5)时,会自动降级尝试init(git-ftp),对应测试test_submodule、test_submodule_catchup、test_submodule_syncroot(tests/git-ftp-test.sh)。
  • 嵌套分支名 scope:作用域名允许/字符,正则校验为^[-0-9a-zA-Z_/]*$(git-ftp 与 git-ftp),测试用例test_scopes_using_nested_branchname专门覆盖(tests/git-ftp-test.sh)。
  • --insecure与 SSH 密钥传递给子模块:set_submodule_args()会透传--key、--pubkey与--insecure(git-ftp),对应测试test_insecure_submodule(tests/git-ftp-test.sh)。

4. 布尔配置:true/false与insecure、disable-epsv、no-commit

此前insecure等配置只能用1/0表达,1.6.0 在boolean()函数中支持true/false字符串映射为1/0(git-ftp)。三个配置项分别由set_insecure()、set_curl_disable_epsv()、set_merge_args()读取(git-ftp),测试对insecure与disable-epsv的布尔值均有 4 组覆盖(tests/git-ftp-test.sh)。注意disable-epsv与no-commit配置项本身就是本版本新增的。

5. LFTP 动作(download/pull)支持--insecure与 FTPES

handle_lftp_settings()将 FTPES 映射为ftp协议并追加set ftp:ssl-force true、set ftp:ssl-protect-data true、set ftp:ssl-protect-list true;--insecure则映射为set ssl:verify-certificate no(git-ftp)。对应测试test_download_insecure(tests/git-ftp-test.sh)与test_supported_protocol_ftpes(tests/git-ftp-test.sh)。

6. 更好的 curl 错误信息与 pull 的--no-commit

  • check_curl_exit_status()将 curl 的错误码 9(访问被拒绝)、67(登录失败)、78(资源不存在)分别翻译为可读的中文/英文诊断提示(git-ftp)。
  • pull动作支持--no-commit:set_merge_args()检测配置或命令行开关后,向git merge追加--no-commit --no-ff(git-ftp),测试test_pull_no_commit、test_pull_no_commit_config验证(tests/git-ftp-test.sh)。

三、1.5.x:代理支持、钩子路径与 ignore 语义转折

1. 1.5.2:使用core.hooksPath

钩子脚本的定位从硬编码的.git/hooks改为优先读取 Git 配置core.hooksPath,未配置时才回退到.git/hooks。该逻辑同时出现在pre_push_hook()与post_push_hook()(git-ftp)。同版本还修复了.git-ftp.log文件名的配置(对应set_deployed_sha1_file()读取deployedsha1file配置,git-ftp),并更新了 Windows 安装文档(见 INSTALL.md 的 Windows 章节)。

2. 1.5.1:--proxy与配置化--insecure

  • 新增-x/--proxy [protocol://]host[:port]选项,直接透传给 curl:CURL_ARGS+=(--proxy "$CURL_PROXY")(git-ftp)。set_curl_proxy()的读取优先级是:命令行--proxy>git-ftp.proxy配置 > Git 全局http.proxy(git-ftp)。
  • --insecure现在也可以从 git config 读取(set_insecure(),git-ftp),同时保留命令行优先级更高(1.5.0 引入的覆盖语义)。
  • FTPES 支持修复:handle_remote_protocol_options()中 FTPES 被映射为ftp协议并追加 curl 的--ssl选项(git-ftp)。

3. 1.5.0:ignore 文件从正则到 glob 的语义转折

这是过滤规则的关键变更:.git-ftp-ignore从此使用shell glob 模式而非正则表达式。实现中glob_filter()用 Bash 的case $filename in ($pattern)逐模式匹配(git-ftp),规则文件同时支持#注释与空行过滤(filter_ignore_files(),git-ftp)。测试test_ignore_pattern、test_ignore_wildcard_files、test_ignore_git_files覆盖(tests/git-ftp-test.sh)。手册 man/git-ftp.1.md 的 IGNORING FILES 一节给出了config/*、*.txt、*/.gitignore等范例。

此外本版本还包含:

  • 修复"Unknown SHA1 object"(Git > 2.16.0):list_changed_files()中git diff --name-only --no-renames --diff-filter=AM/D -z失败时,-f/--force下直接全量上传,否则交互询问(git-ftp)。
  • 避免 Git 将空字符串作为 pathspec 的警告。
  • 修复使用 exclude 模式执行git ftp download可能误删本地.git目录的 bug。
  • post-ftp-push钩子的参数从"将要部署的 SHA1"修正为"上次已部署的 SHA1"(PREV_DEPLOYED_SHA1,git-ftp)。
  • 新增 curl 存在性及协议支持检查check_curl_access()(git-ftp)。
  • 文档层面补充了 GIT LFS 用法、git-ftp.remote-root配置与 SFTP 说明。

四、1.4.0 与 1.3.x:密钥解耦与自动初始化

1. 1.4.0:--key/--pubkey解耦与未知远程提交

  • SFTP 场景下--key与--pubkey不再绑定,可独立指定;若只给了私钥而公钥缺失,脚本会自动尝试同目录下的${private_key}.pub(git-ftp)。
  • --cacert参数处理更安全:仅在协议为ftps/ftpes且文件存在可读时才追加(git-ftp)。
  • 脚本中失败条件收紧:如果服务器.git-ftp.log中的提交 ID 在本地 Git 对象库中不存在,脚本不再静默继续,而是失败退出——这正是"Fail in scripts if remote commit is unknown"的语义,交互逻辑见list_changed_files()(git-ftp)。
  • 文档方面扩充了.git-ftp-include与.git-ftp-ignore的说明。

2. 1.3.3/1.3.2:--auto-init与 busybox 兼容

  • --auto-init:push 时若远程不存在.git-ftp.log,自动执行 init 逻辑(全量上传)而无需手动先 init。实现位于set_deployed_sha1_for_push():AUTO_INIT=1时先尝试非致命读取,若DEPLOYED_SHA1为空则设置IGNORE_DEPLOYED=1(git-ftp),测试test_auto_init验证(tests/git-ftp-test.sh)。
  • mktmp改用更长的模式串以兼容 busybox 环境(mktemp -d -t git-ftp-XXXXXX,git-ftp)。

五、1.3.0:钩子系统、增量拉取与快照动作

1. 客户端钩子:pre-ftp-push与post-ftp-push

钩子机制是本版本最浓墨重彩的工程特性,运行于init与push动作(源码中的调用时序见 git-ftp):

  • 触发时机:pre-ftp-push在变更集生成之后、真正上传之前调用;post-ftp-push在传输结束后调用。
  • 四个参数:$1作用域名(未设置时为主机名)、$2目标 URL、$3本地即将部署的提交 ID、$4服务器上将被更新的远程提交 ID。
  • 标准输入:NUL 字节分隔的文件清单,每条为A <path>或D <path>(A=上传、D=删除)。该清单是经过.git-ftp-include/.git-ftp-ignore规则修正后的最终同步集,与git diff的原始输出不同。生成逻辑在print_status()(git-ftp)。
  • 退出语义:pre-ftp-push非零退出 → 中止并以错误码 9(ERROR_HOOK)退出;post-ftp-push默认忽略失败,仅在--enable-post-errors下失败才报错(git-ftp)。--no-verify只绕过 pre 钩子,--no-post-hooks绕过 post 钩子。
  • 测试佐证:test_pre_push、test_post_push、test_post_push_arguments_first/repeated、test_post_push_no_fail/fail全面覆盖(tests/git-ftp-test.sh)。
  • 手册中附带一个完整示例:在 pre 钩子中扫描待上传文件,发现含TODO字样即拒绝上传(见 man/git-ftp.1.md 的 HOOKS 一节)。

2.--changed-only:拉取时只镜像差异文件

在pull的 lftp mirror 阶段,只考虑自部署提交以来变更过的文件。实现上通过git diff "$CURRENT_BRANCH" --name-only逐文件生成 lftp 的--include参数,同时关闭--delete并排除隐藏文件(git-ftp),测试test_pull_changedonly验证(tests/git-ftp-test.sh)。

3.snapshot动作:将远程目录拉取为全新 Git 仓库

git ftp snapshot ftp://example.com/public_html projects/example

action_snapshot()的流程是:校验 lftp → 初始化本地仓库(目标目录必须为空且无.git-ftp.log,否则拒绝)→ lftp mirror 下载 →git add . && git commit→ 最后执行 catchup 记录部署状态(git-ftp、git-ftp),测试test_snapshot与test_snapshot_fail覆盖(tests/git-ftp-test.sh)。

4. 其他 1.3.0 变更

  • 文件列表生成性能优化:handle_file_sync()使用sort -z -u去重排序(git-ftp)。
  • 允许文件名以-开头(对应测试test_file_with_dash,tests/git-ftp-test.sh)。
  • 测试环境配套 vsftpd 配置文件(tests/vsftpd.conf),测试说明见 tests/README.md。
  • include 算法与 ignore 列表解耦、include 中前导/按 Git 语义视为仓库根(add_include_files(),git-ftp)。

六、1.2.0-rc.1:双向同步能力——download 与 pull

1. 文件选择算法的重构

  • --diff-filter:改用git diff --diff-filter=AM -z与--diff-filter=D -z分别生成上传与删除清单,彻底替代旧的文件枚举方式(git-ftp)。
  • NUL 分隔文件名:所有内部文件列表改为\0分隔,避免文件名含换行/空格时的解析歧义。
  • curl 对文件名做 URL 编码:upload_file_buffered()中#与空格分别编码为%23、%20(git-ftp),对应测试test_file_with_spaces、test_file_with_nonchar、test_file_with_unicode(tests/git-ftp-test.sh)。
  • .git-ftp-include在无文件变更时也生效:include 对照基线默认取空树哈希git hash-object -t tree /dev/null(git-ftp)。

2. 子模块的早期修复

  • 抑制 Git 2.7 的 submodule status 报错:cache_git_submodules()用2>/dev/null并过滤未初始化的子模块(grep -v '^-')(git-ftp)。

3. 拉取功能的内幕

pull本质上是download的自动化封装,其内部步骤为(见 man/git-ftp.1.md 的 DOWNLOADING FILES 一节,源码实现于handle_fetch(),git-ftp):

git checkout <remote-commit> git ftp download git add --all git commit -m '[git-ftp] remotely untracked modifications' git ftp catchup git checkout <my-branch> git merge <new-remote-commit>

handle_fetch()中值得注意的工程细节:切换 commit 前会用git stash -u暂存本地未跟踪文件(防止.gitignore跨提交变化导致残留),合并前恢复 stash;download_remote_updates()通过lftp -e执行mirror --delete . <SYNCROOT>(git-ftp)。

警告:download会删除不在.git-ftp-ignore中的本地未跟踪文件,使用前请务必确认规则文件完整(check_for_untracked_files()会在下载前做脏工作区检查,git-ftp)。

七、1.1.0-rc.1 与 1.0.x:缓冲、glob 与 5 倍提速

1. 上传/删除缓冲:curl 配置文件批量操作

1.1.0 引入了"在 curl config 文件中缓冲上传与删除指令"的机制。upload_file_buffered()将每个文件的-T与url写入临时文件,最后fire_upload_buffer()通过curl -K <config>一次连接批量执行(git-ftp)。删除操作同理(delete_file_buffered()/fire_delete_buffer(),git-ftp)。

这直接关联 0.8.0 的一项里程碑:"using a single connection for all uploads now. This makes git-ftp 5x faster!"——所有上传复用单条 curl 连接,CHANGELOG 明确记录了 5 倍性能提升(该结论为项目维护者的原记录,非本文推测)。删除缓冲的另一个动机是防止文件过多时触发ARG_MAX(1.0.0 的"Fire before ARG_MAX reached")。

2. glob 过滤与 URL 编码

  • 过滤规则从正则迁移到 glob 始于 1.1.0(Maikel Linke 贡献),1.5.0 正式成文。
  • urlencode()对用户名与密码做百分号编码后嵌入 curl URL(git-ftp),避免特殊字符破坏 URL 结构。

3. 密码输入语义:-P与-p的职责分离

René Moser 在 1.1.0 中确立了明确约定:-P/--ask-passwd用于交互式输入密码,-p/--passwd只用于命令行传递密码(ask_for_passwd()使用stty -echo隐藏输入,git-ftp)。这条约定延续至今,并在手册 PASSWORDS 一节有详细的安全提醒(特殊字符单引号引用、以-开头的密码建议改用git config默认值、~/.netrc或--ask-passwd)。

4. 1.0.0 的稳定性收尾

  • 远程访问预检:check_remote_access()在上传前先探测服务器连通性(git-ftp)。
  • 提交 ID 同步时序修复:仅在确有文件推送后才更新服务器上的 SHA1(upload_local_sha1()仅在handle_file_sync后调用);修复了upload_sha1时机、计数 bug(handle_file_sync()的DONE_ITEMS计数)与上传缓冲长度检查。
  • 防止误删未纳入版本控制的文件、修复删除缓冲在 ARG_MAX 前触发。
  • --remote-root(iKasty 贡献):指定远程根目录,URL 中的路径部分被忽略(set_remote_path(),git-ftp),对应配置git-ftp.remote-root。
  • 子模块 catchup(submodule_catchup(),git-ftp)、scope 中不允许空格、失败删除动作的错误级别修正。

八、0.9.0 与 0.8.x:早期功能成型期

1.log动作:直接查看远程部署提交

action_log()下载服务器上的.git-ftp.log,取得部署 SHA1 后执行git log <sha1>(git-ftp);配套的show动作则执行git show。这使运维人员无需额外工具即可确认服务器当前处于哪个提交。

2.--scope的便捷语义:无参时使用当前分支名

0.8.1 起,-s/--scope后不跟参数时,自动取当前分支名作为 scope(git-ftp)——这正是 1.6.0 嵌套分支名支持的基础,测试test_scopes_using_branchname_as_scope验证(tests/git-ftp-test.sh)。

3.--insecure与--cacert

0.8.1 引入两个 TLS 相关选项:--insecure跳过服务器证书校验(源码中映射为 curl 的-k,git-ftp),--cacert指定自定义 CA 证书库。两者均支持 git config 配置。注意手册明确警告:--insecure会暴露于中间人攻击,仅比裸 FTP 略安全。

4. 0.7.x 的作用域与 ignore 基础

  • add-scope/remove-scope动作:set_scope()解析user:password@host形式的 URL,自动拆分为git-ftp.<scope>.url、.user、.password三项配置(多个:时仅设置 URL 并提示用--user/--passwd,git-ftp);remove_scope()用git config --remove-section整体删除(git-ftp)。
  • .git-ftp-ignore支持注释与空白:grep -v '^#.*$\|^\s*$'过滤(git-ftp)。
  • 修复路径含空格、syncroot 相关 bug,移除并行连接特性(为后续单连接优化铺路)。

九、从 CHANGELOG 到可复现:测试体系与部署实践

1. 测试环境的搭建方式

项目核心功能使用 shunit2 做单元测试,测试脚本 tests/git-ftp-test.sh 共包含约 120 个测试用例(从test_displays_usage到test_post_push_fail)。运行方式(详见 tests/README.md):

# 通过环境变量指定测试用 FTP 服务器 export GIT_FTP_HOST=localhost export GIT_FTP_PORT=:2121 # 冒号是必需的 export GIT_FTP_ROOT=test_dir export GIT_FTP_USER=kate export GIT_FTP_PASSWD=s3cret make # 在 tests 目录下执行

仓库自带 vsftpd 3.0.3 的 Linux(Debian 7 编译)与 macOS 二进制及配置文件(tests/vsftpd-3.0.3.debian7、tests/vsftpd-3.0.3.el_capitan、tests/vsftpd.conf),并附带 lftp 4.6.0 的 pkg 包(tests/lftp-4.6.0-0.pkg)。若未安装 lftp,测试会在服务器留下git-ftp-XXXX命名的临时目录,需手动清理。

2. 安装与升级

安装方式完整记录在 INSTALL.md,核心途径包括:

  • make 安装:sudo make install(或make install-all连同手册),Makefile 定义了install/install-man/uninstall等目标。
  • 直接下载脚本:将 git-ftp 脚本放入bin目录并赋予 755 权限。
  • 包管理器:Debian/Ubuntuapt-get install git-ftp(或 PPA)、Homebrewbrew install git-ftp(macOS)。
  • 注意 macOS 自带 curl 默认不支持 SFTP 协议,需自行编译带 libssh2 的 curl(INSTALL.md 有完整步骤)。

3. 实战联动:配置默认值、作用域与钩子的组合

从 CHANGELOG 的演进可以看出,git-ftp 的配置体系最终收敛为三层叠加:

# 第一层:全局默认(DEFAULTS) git config git-ftp.url ftp.example.com git config git-ftp.user john git config git-ftp.password secr3t git config git-ftp.remote-root htdocs git config git-ftp.insecure false # 1.6.0 起支持布尔值 # 第二层:作用域覆盖(SCOPES,可含嵌套分支名) git config git-ftp.production.url live.example.com git config git-ftp.production.user manager git config git-ftp.production.password n0tThatSimp3l # 第三层:命令行选项(优先级最高) git ftp push -s production --insecure

读取优先级在get_config()中体现:git-ftp.<scope>.<key>>git-ftp.<key>> 内置默认值(git-ftp),且支持.git-ftp-config独立配置文件。

十、结语:版本史背后的工程取舍

纵观 CHANGELOG,git-ftp 的演进呈现三条清晰脉络:

  1. 性能:从逐文件连接(0.8.0 前)→ 单连接批量缓冲(0.8.0,5x 提速)→ 缓冲防 ARG_MAX(1.0.0)→ 文件列表生成优化(1.3.0)。
  2. 健壮性:远程预检(1.0.0)、未知提交失败(1.4.0)、curl 能力检查(1.5.0)、退出码语义修正(1.6.0)。
  3. 能力扩展:作用域(0.7.3)→ 双向同步 download/pull(1.2.0)→ 钩子系统与 snapshot(1.3.0)→ 代理与 FTPES(1.5.1)→ LFTP 全协议支持(1.6.0)。

对于使用者而言,最值得吸收的实践是:增量部署的可靠性建立在"远程 SHA1 状态"这一单一事实来源之上,.git-ftp-ignore/.git-ftp-include的 glob 规则、pre-ftp-push钩子的前置校验、以及--dry-run的预演,构成了安全部署的完整闭环。若需查阅更完整的选项与语义,请以 man/git-ftp.1.md 手册为准;如需复现各版本的测试行为,可参照 tests/git-ftp-test.sh 与 tests/vsftpd.conf。

  • 开发工具
  • CLI
  • DevOps

【免费下载链接】git-ftp

Uses Git to upload only changed files to FTP servers.

项目地址:https://gitcode.com/gh_mirrors/gi/git-ftp
点击查看免费下载
上一篇:3分钟搞定GitHub中文界面:让编程学习不再有语言障碍
下一篇:2026年开发者福音:三分钟掌握JetBrains IDE试用期无限重置技巧

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询