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.