This Python git-ftp is a port of the Bash git-ftp, version 1.6.0. The rule of the port is: keep everything on the wire and in configuration identical, fix the bugs, and write down every deviation here.
A remote deployed with the Bash git-ftp can be picked up by this port and vice
versa. The deployed-commit file (.git-ftp.log), its content, the config keys,
the .git-ftp-ignore and .git-ftp-include formats, the hook names and
arguments, the exit codes and the default progress messages are unchanged.
| Area | Status |
|---|---|
Actions init, push, catchup, show, log, download, pull, snapshot, add-scope, remove-scope, help, version |
Same names, same semantics |
| Options | Every 1.6.0 option is accepted with the same spelling |
Config keys git-ftp.* and git-ftp.<scope>.*, .git-ftp-config |
Same keys, same precedence, an explicit empty value still overrides |
.git-ftp.log (or git-ftp.deployedsha1file) |
Same location and content (commit id plus newline) |
.git-ftp-ignore |
Same glob semantics: * crosses /, patterns match the whole Git path including the syncroot |
.git-ftp-include |
Same !target and target:source forms, same directory/missing-target rules, applied before ignore |
Hooks pre-ftp-push, post-ftp-push |
Same arguments and stdin format |
| Exit codes | 2 usage, 3 missing argument, 4 upload, 5 download, 6 unknown protocol, 7 locked, 8 git, 9 hook, 10 filesystem |
| Progress output | N file(s) to sync:, [i of N] Buffered for upload '…'., Uploading ..., Last deployment changed from … to …., etc. |
~/.netrc fallback when no user is given |
Same, now also for sftp |
| Remote lock semantics | Same file (git-ftp.lck), checked and written only with --lock, same "a lock for my own commit is mine" rule |
| Empty remote directories | Kept, as upstream since 1.1.0 (issue #168) |
These are behaviours of the Bash script that are clearly unintended. Each is fixed rather than reproduced.
--no-verifyand--enable-post-errorsswallowed the argument after them.--key=FILE,--pubkey=FILEand--branch=NAMEwere not parsed.--silentalso suppressed fatal error messages, and-vsent them to stdout. Fatal errors now always go to stderr, at every verbosity.--remote-rootwas prepended to the URL's path although the manual says it replaces it. It replaces it.--locktoggled: giving it twice turned locking off. It is a plain flag.- The lock file's two lines were joined by a literal
\n. A real newline is written; both forms are read. - The lock file was named after the script's own file name. The name is fixed.
ftp://user@host/pathtookuserfor the host. Userinfo in a URL is parsed as credentials.host:2121/pathwithout a scheme was rejected as an unknown protocol even though the built-in help shows that form. It is accepted as ftp.add-scopegave up on a URL whose password contained a colon or an at-sign.- File names containing
%,?,[,],"or a backslash were mangled on the way into curl. They are transferred intact. So is a file named-. git-ftp.no-commit falseenabled the option. Booleans are parsed as Git parses them (true/yes/on/1andfalse/no/off/0).- A push whose remote log could not be read for any reason said "use 'git ftp init'". That message is now reserved for a genuinely missing log; a wrong password or an unreachable host is reported as what it is.
- The delete phase ran a directory listing of the remote root just to have a
transfer to attach
-Qcommands to. Deletes are plainDELEcommands. - Files whose type changed (a file becoming a symlink or vice versa,
Tingit diff) were never uploaded. They are. - Running from a subdirectory of the repository resolved
--syncrootand the submodule list against the wrong directory. catchupwith more than one submodule only handled the first one, andcd-ed deeper with every iteration.- Passwords were visible on the curl command line (
ps). Credentials are passed to libcurl in memory and never appear in URLs, logs or argv. - Temporary files were left behind on Ctrl-C. There are no temporary files.
- Parallel transfers:
--jobs N/git-ftp.jobs(default 4,1is sequential). Uploads run first, then deletes, and the commit log is written last, only when every upload succeeded. The first failed upload stops the deploy (exit 4); failed deletes are warnings, as upstream. - Native
download,pullandsnapshot: nolftpneeded. Listings useMLSDwith aLISTfallback; downloads are parallel too. - Submodules are deployed in-process (no recursive
git-ftpinvocation). - Environment variables
GIT_FTP_URL,GIT_FTP_USER,GIT_FTP_PASSWORD, read after the command line and before Git configuration. --password-command/git-ftp.password-command: a shell command whose first output line is the password.unlockaction to remove a stale lock left by an interrupted deploy.--key-passphrase/git-ftp.key-passphrase, and an interactive prompt, for encrypted SFTP keys. Upstream cannot use an encrypted key at all.- SFTP authentication through a running
ssh-agent(SSH_AUTH_SOCK). --passwordas an alias of--passwd;--no-post-hooks.- Ctrl-C stops the transfers promptly and exits with 130.
version -vprints the libcurl and paramiko versions in use.- An interactive terminal shows a progress spinner with a
done/totalcount while files upload, delete or download; it renders on stderr and is silent when output is not a terminal or under-n. --worktree/git-ftp.worktree:initandpushread the upload from a temporary Git worktree checked out at the deployed commit, so edits to the working tree during the upload cannot leak in. Untracked files added by.git-ftp-includeare read from the live working tree, since a worktree of the commit cannot contain them.
- SFTP host keys are verified against
~/.ssh/known_hostsand/etc/ssh/ssh_known_hosts. Upstream accepted any host key silently. An unknown host is refused with a pointer tossh-keyscan;--insecureturns verification off, as it does for TLS. - SFTP is spoken by paramiko, not libcurl. FTP, FTPS and FTPES use libcurl through pycurl.
gitis required at run time (the port shells out to it, as upstream).- A valueless boolean key such as a bare
insecureline in.git-ftp-configreads as true, exactly asgit configreads it. - Diagnostics printed with
-vgo to stderr with a timestamp; progress lines stay on stdout. Warnings (WARNING: …) go to stderr at every verbosity. ftps://andftpes://require TLS 1.2 or newer and encrypt the data connection as well as the control connection.-u,-sand-kwithout an argument work as upstream (local user, current branch, default keychain item). An action name after a bare flag (-u push) is recognised as the action.- The
Insecure is 'N'.andDisable EPSV is '1'.diagnostics are printed once per repository (twice with one submodule), as upstream. download --changed-onlyuses the deployed commit to pick the files (upstream ignored the flag fordownload).- The macOS keychain is read through the
securitycommand on macOS and ignored elsewhere, as upstream. Keychain entries cannot unlock SSH keys.
download,pullandsnapshotnever print lftp's transfer log; they print a one-line summary instead (Downloaded N file(s), deleted M local file(s).).