Compatibility between the implementations¶
What the Python port keeps identical to the Bash original, which of its bugs it fixes, and where it deliberately behaves differently.
Synced from upstream
This page is generated from its source in the tool's repository and is refreshed every time the site is built. Edit it there, not here.
Compatibility with git-ftp 1.6.0¶
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.
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) |
Upstream bugs that are fixed¶
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.
New¶
- 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.
Behaviour that differs on purpose¶
- 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.
Not implemented¶
download,pullandsnapshotnever print lftp's transfer log; they print a one-line summary instead (Downloaded N file(s), deleted M local file(s).).