- 开发工具
- CLI
- DevOps
【免费下载链接】git-ftp
Uses Git to upload only changed files to FTP servers.
导读:本文以 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 中几乎所有变更都围绕这三条主线展开:
- 增量上传:git-ftp 是一个"Git 驱动的 FTP 客户端",它借助
git diff判断自上次部署以来本地哪些文件发生了变化,只上传这些文件,从而节省带宽与时间(见 README.md 开篇说明)。 - 远程状态跟踪:git-ftp 将"最后一次部署的提交 SHA1"写入服务器上的
.git-ftp.log文件(默认文件名,可用deployedsha1file配置覆盖),远程主机上无需安装 Git。set_deployed_sha1_file()与upload_local_sha1()分别对应读取与写入逻辑(git-ftp、git-ftp)。 - 双引擎架构:上传、删除、日志读取等"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/exampleaction_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/Ubuntu
apt-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 的演进呈现三条清晰脉络:
- 性能:从逐文件连接(0.8.0 前)→ 单连接批量缓冲(0.8.0,5x 提速)→ 缓冲防 ARG_MAX(1.0.0)→ 文件列表生成优化(1.3.0)。
- 健壮性:远程预检(1.0.0)、未知提交失败(1.4.0)、curl 能力检查(1.5.0)、退出码语义修正(1.6.0)。
- 能力扩展:作用域(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.
相关推荐
git-ftp 多协议支持:FTP、SFTP、FTPS、FTPES 全攻略
git ftp 多协议支持:FTP、SFTP、FTPS、FTPES 全攻略 想要快速部署网站文件到服务器?git ftp 是您的终极解决方案!这个强大的 Git
开发工具CLIDevOpsGit-ftp 技术详解:基于Git的智能FTP部署工具
Git ftp 技术详解:基于Git的智能FTP部署工具 什么是Git ftp Git ftp是一款基于Git版本控制的智能FTP客户端工具,它通过分析Git仓
开发工具CLIDevOps使用Git进行FTP部署:git-ftp工具入门指南
使用Git进行FTP部署:git ftp工具入门指南 目录结构及介绍 在克隆了 git ftp 项目后,你会看到以下主要目录: bin : 包含用于不同操作系统
开发工具CLIDevOps
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考