It's not too hard to statically compile a copy of Git yourself, you can follow these instructions. I used a Musl cross compiler so the resulting binaries are completely static; they don't even link with glibc (which is a huge pain to deal with). It's not perfect though (see below):
# Download git and a musl compiler so that we don't depend on shitty glibc.
wget https://www.kernel.org/pub/software/scm/git/git-2.31.1.tar.gz
wget http://musl.cc/x86_64-linux-musl-cross.tgz
tar xvf git-2.31.1.tar.gz
tar xvf x86_64-linux-musl-cross.tgz
# Add the compiler to our path.
export PATH="$(pwd)/x86_64-linux-musl-cross/bin:$PATH"
cd git-2.31.1/
# Make output directory.
mkdir output
# Configure to use the musl compiler with static linking.
export CFLAGS="$CFLAGS -static"
./configure --build x86_64-linux-musl-cross --prefix="$(pwd)/output"
# Disable various dependencies to make it easier to compiler & link.
# Note that this means you can't use the https transport, you can still use
# ssh though. See https://github.com/git/git/blob/master/Makefile
make NO_OPENSSL=1 NO_CURL=1 NO_EXPAT=1 NO_GETTEXT=1 NO_PERL=1 NO_PYTHON=1 NO_TCLTK=1 -j8 install
Unfortunately Git started as a bunch of hacky shell scripts - and some parts are still shell scripts! So it compiles to a ton of separate binaries rather than a single one like you might expect from a well designed program, however it does work. You get an output directory like this:
$ tree
.
├── bin
│ ├── git
│ ├── git-cvsserver
│ ├── git-receive-pack
│ ├── git-shell
│ ├── git-upload-archive
│ └── git-upload-pack
├── libexec
│ └── git-core
│ ├── git
│ ├── git-add
│ ├── git-add--interactive
│ ├── git-am
│ ├── git-annotate
│ ├── git-apply
│ ├── git-archimport
│ ├── git-archive
│ ├── git-bisect
│ ├── git-bisect--helper
│ ├── git-blame
│ ├── git-branch
│ ├── git-bugreport
│ ├── git-bundle
│ ├── git-cat-file
│ ├── git-check-attr
│ ├── git-check-ignore
│ ├── git-check-mailmap
│ ├── git-checkout
│ ├── git-checkout-index
│ ├── git-check-ref-format
│ ├── git-cherry
│ ├── git-cherry-pick
│ ├── git-clean
│ ├── git-clone
│ ├── git-column
│ ├── git-commit
│ ├── git-commit-graph
│ ├── git-commit-tree
│ ├── git-config
│ ├── git-count-objects
│ ├── git-credential
│ ├── git-credential-cache
│ ├── git-credential-cache--daemon
│ ├── git-credential-store
│ ├── git-cvsexportcommit
│ ├── git-cvsimport
│ ├── git-cvsserver
│ ├── git-daemon
│ ├── git-describe
│ ├── git-diff
│ ├── git-diff-files
│ ├── git-diff-index
│ ├── git-difftool
│ ├── git-difftool--helper
│ ├── git-diff-tree
│ ├── git-env--helper
│ ├── git-fast-export
│ ├── git-fast-import
│ ├── git-fetch
│ ├── git-fetch-pack
│ ├── git-filter-branch
│ ├── git-fmt-merge-msg
│ ├── git-for-each-ref
│ ├── git-for-each-repo
│ ├── git-format-patch
│ ├── git-fsck
│ ├── git-fsck-objects
│ ├── git-gc
│ ├── git-get-tar-commit-id
│ ├── git-grep
│ ├── git-hash-object
│ ├── git-help
│ ├── git-http-backend
│ ├── git-imap-send
│ ├── git-index-pack
│ ├── git-init
│ ├── git-init-db
│ ├── git-instaweb
│ ├── git-interpret-trailers
│ ├── git-log
│ ├── git-ls-files
│ ├── git-ls-remote
│ ├── git-ls-tree
│ ├── git-mailinfo
│ ├── git-mailsplit
│ ├── git-maintenance
│ ├── git-merge
│ ├── git-merge-base
│ ├── git-merge-file
│ ├── git-merge-index
│ ├── git-merge-octopus
│ ├── git-merge-one-file
│ ├── git-merge-ours
│ ├── git-merge-recursive
│ ├── git-merge-resolve
│ ├── git-merge-subtree
│ ├── git-mergetool
│ ├── git-mergetool--lib
│ ├── git-merge-tree
│ ├── git-mktag
│ ├── git-mktree
│ ├── git-multi-pack-index
│ ├── git-mv
│ ├── git-name-rev
│ ├── git-notes
│ ├── git-p4
│ ├── git-pack-objects
│ ├── git-pack-redundant
│ ├── git-pack-refs
│ ├── git-patch-id
│ ├── git-prune
│ ├── git-prune-packed
│ ├── git-pull
│ ├── git-push
│ ├── git-quiltimport
│ ├── git-range-diff
│ ├── git-read-tree
│ ├── git-rebase
│ ├── git-rebase--preserve-merges
│ ├── git-receive-pack
│ ├── git-reflog
│ ├── git-remote
│ ├── git-remote-ext
│ ├── git-remote-fd
│ ├── git-repack
│ ├── git-replace
│ ├── git-request-pull
│ ├── git-rerere
│ ├── git-reset
│ ├── git-restore
│ ├── git-revert
│ ├── git-rev-list
│ ├── git-rev-parse
│ ├── git-rm
│ ├── git-send-email
│ ├── git-send-pack
│ ├── git-shell
│ ├── git-sh-i18n
│ ├── git-sh-i18n--envsubst
│ ├── git-shortlog
│ ├── git-show
│ ├── git-show-branch
│ ├── git-show-index
│ ├── git-show-ref
│ ├── git-sh-setup
│ ├── git-sparse-checkout
│ ├── git-stage
│ ├── git-stash
│ ├── git-status
│ ├── git-stripspace
│ ├── git-submodule
│ ├── git-submodule--helper
│ ├── git-svn
│ ├── git-switch
│ ├── git-symbolic-ref
│ ├── git-tag
│ ├── git-unpack-file
│ ├── git-unpack-objects
│ ├── git-update-index
│ ├── git-update-ref
│ ├── git-update-server-info
│ ├── git-upload-archive
│ ├── git-upload-pack
│ ├── git-var
│ ├── git-verify-commit
│ ├── git-verify-pack
│ ├── git-verify-tag
│ ├── git-web--browse
│ ├── git-whatchanged
│ ├── git-worktree
│ ├── git-write-tree
│ └── mergetools
│ ├── araxis
│ ├── bc
│ ├── codecompare
│ ├── deltawalker
│ ├── diffmerge
│ ├── diffuse
│ ├── ecmerge
│ ├── emerge
│ ├── examdiff
│ ├── guiffy
│ ├── gvimdiff
│ ├── kdiff3
│ ├── kompare
│ ├── meld
│ ├── nvimdiff
│ ├── opendiff
│ ├── p4merge
│ ├── smerge
│ ├── tkdiff
│ ├── tortoisemerge
│ ├── vimdiff
│ ├── winmerge
│ └── xxdiff
└── share
└── git-core
└── templates
├── branches
├── description
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── pre-merge-commit.sample
│ ├── prepare-commit-msg.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ ├── push-to-checkout.sample
│ └── update.sample
└── info
└── exclude
10 directories, 206 files
Add the bin directory to your PATH and you should be good to go! There are two caveats:
We disabled OpenSSL and Curl and so on which means you can't use https:// URLs - only ssh://.
If you move it anywhere, you get warnings about missing templates.
This is because it uses autotools (another big hack) and autotools pretty much refuses to acknowledge that people might want portable programs, so you have to install it to a compile-time fixed absolute path. Git uses that to locate the templates directory, so if you move the output directory anywhere else you start getting warnings like this:
warning: templates not found in /home/tim/local/git-2.31.1/output/share/git-core/templates
However for some reason all of the git commands themselves work fine - you can do git init, git log and so on and it somehow finds the libexec/git_core directory even if you move it.