在Windows上构建嵌入式git以用于clone和pull

Author Avatar
Lussac 5月18日 ; Views: 98
  • 在其它设备中阅读本文章

在编写应用程序时,我们可能需要或倾向于使用 git 来克隆 GitHub 上的仓库,但又不希望要求用户必须提前安装完整的 Git 。如何构建一个嵌入式、绿色便携的 git 以供 git clonegit pull

获取 git-embed

GitHub Stars

platform GitHub release Latest version of Git GitHub All Releases

GitHub Releases 页面 下载最新发布的的 "git-embed" 。国内用户可以从 这里 下载。


尝试

  • 一种方式是使用 libgit2 ,其支持任何能够调用 C 语言库 的 编程语言
  • 另一种方法是从 git-for-windows 中提取出能完成 git clonegit pull 的最小程序集。

本文将尝试第二种方式。出于兼容性考虑,选择从 32 位的 Git 中提取构建,即 Git-2.26.2-32-bit.exeMinGit-2.26.2-32-bit.zipPortableGit-2.26.2-32-bit.7z.exe 。下文以 PortableGit-2.26.2-32-bit.7z.exe 为例。(其实 )

git.exe

通过在已完整安装 Git 的 Windows 上运行 git --exec-path 可以知道 git.exe 位于 Git 安装目录下的 mingw64/libexec/git-core/ 文件夹下。故可以(用 7-zip, WinRAR 等 )打开 PortableGit-2.26.2-32-bit.7z.exe 并解压之。准备一个未安装 Git 的 Windows7 虚拟机,复制 mingw32/libexec/git-core/git.exe 到虚拟机任意文件夹内。

DLL 依赖

可以预见只有一个 git.exe 必然无法完成 git clonegit pull ,我们需要找到还有哪些必要的 dll 库文件。
在当前目录打开 CMD 尝试执行 git 命令:

$ git

无法启动此程序,因为计算机中丢失 libiconv-2.dll。尝试重新安装该程序以解决此问题。

据此不断把 mingw32/libexec/git-core/ 中相应的 .dll 文件复制到虚拟机内,与 git.exe 同一级目录即可。对于 v2.26.2 ,可知必须的 dll 库文件有:

  • libiconv-2.dll
  • libgcc_s_dw2-1.dll
  • libwinpthread-1.dll
  • libintl-8.dll
  • libpcre2-8-0.dll
  • zlib1.dll
  • libssp-0.dll

现在 git 能正确显示帮助信息了:

$ git
usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]

These are common Git commands used in various situations:

...

目前整体文件大小约为 5.15 MB ,经 zip 压缩后约为 2.58 MB 。

git clone

现在来测试 git clone 能否成功执行:

$ git clone https://github.com/LussacZheng/video-downloader-deploy.git
Cloning into 'video-downloader-deploy'...
warning: templates not found in /mingw32/share/git-core/templates
fatal: unable to find remote helper for 'https'

templates 的警告暂且不管。实际上只需要复制 mingw32/share/git-core/templates/ 文件夹到 git.exe 所在目录,并指定 --template 参数即可:

$ git clone https://github.com/LussacZheng/video-downloader-deploy.git --template ./templates
Cloning into 'video-downloader-deploy'...
fatal: unable to find remote helper for 'https'

所以下文我会省略 --template 参数并刻意删去 warning: templates not found... 的警告信息。

而这个关于 https 的报错,我搜索到两种解决方案,先看最简单的方案。

https 错误 解决方案 1

将仓库地址中的 https:// 替换为 git:// ,即:

$ git clone git://github.com/LussacZheng/video-downloader-deploy.git
Cloning into 'video-downloader-deploy'...
error: cannot spawn git: No such file or directory
fatal: fetch-pack: unable to fork off index-pack
fatal: read error: Bad file descriptor

在 StackOverflow 上找到了 类似的问题。经尝试,只需要将 git.exe 所在目录加入环境变量 PATH 即可。

对于 CMD 窗口,可以使用 set 命令:( .\ 是当前目录,实际嵌入后需要根据情况修改,如 set "PATH=%PATH%;D:\my\path\to\git\dir"

> set "PATH=%PATH%;.\"
> git clone git://github.com/LussacZheng/video-downloader-deploy.git
Cloning into 'video-downloader-deploy'...
remote: Enumerating objects: 70, done.
remote: Counting objects: 100% (70/70), done.
remote: Compressing objects: 100% (48/48), done.
remote: Total 70 (delta 33), reused 53 (delta 21), pack-reused 0Receiving objects:  34% (24/70), 1

Receiving objects: 100% (70/70), 15.56 KiB | 14.00 KiB/s, done.
Resolving deltas: 100% (33/33), done.

可以看到已经能够成功 clone 了。

https 错误 解决方案 2

git clone https://... 命令执行时实际上会调用 git-remote-https.exe 。另外 git-remote-http.exe 等同理。
既然如此,便将 git-remote-https.exe 复制到文件夹内。

$ git-remote-https

无法启动此程序,因为计算机中丢失 libcurl-4.dll。尝试重新安装该程序以解决此问题。

相似地,可以试出其还依赖于以下 dll 文件:

  • libcurl-4.dll
  • libcrypto-1_1.dll
  • libidn2-0.dll
  • libunistring-2.dll
  • libnghttp2-14.dll
  • libssh2-1.dll
  • libssl-1_1.dll

只不过这样一来,会导致整体文件大小增加约 8.16 MB 。

REM set "PATH=%PATH%;.\"

> git clone https://github.com/LussacZheng/video-downloader-deploy.git
Cloning into 'video-downloader-deploy'...
fatal: unable to access 'https://github.com/LussacZheng/video-downloader-deploy.git/': error setting certificate verify locations:
  CAfile: C:/Users/admin/Desktop/git/ssl/certs/ca-bundle.crt
  CApath: none

对于 SSL 证书问题,可以:

  1. 复制 mingw32/ssl/certs/ca-bundle.crt 文件并指定 -c http.sslcainfo=path/to/crt

    $ git clone https://github.com/LussacZheng/video-downloader-deploy.git -c http.sslcainfo=ca-bundle.crt
    Cloning into 'video-downloader-deploy'...
    remote: Enumerating objects: 70, done.
    remote: Counting objects: 100% (70/70), done.
    remote: Compressing objects: 100% (48/48), done.
    remote: Total 70 (delta 33), reused 53 (delta 21),    pack-reused 0R
    Receiving objects: 100% (70/70), 15.56 KiB | 3.89 MiB/s,    done.
    Resolving deltas: 100% (33/33), done.
    `ca-bundle.crt` 会导致整体文件大小增加约 195 KB 。
    
  2. 或者还可以通过 -c http.sslverify=false 来取消 SSL 认证:
    $ git clone https://github.com/LussacZheng/video-downloader-deploy.git -c http.sslverify=false

git pull

现在来测试 git pull 能否成功执行。

可以创建一个测试项目,先在虚拟机内 clone 再在宿主机上 commit, push 一次。之后即可测试 git pull

$ git pull
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 0), reused 4 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), 1.06 KiB | 20.00 KiB/s, done.
From https://github.com/LussacZheng/test
   b65c4e3..2141f21  pull-test  -> origin/pull-test
Updating b65c4e3..2141f21
Fast-forward
 another.txt     | 5 +++++
 new.txt         | 2 ++
 test.bat        | 6 ------
 3 files changed, 7 insertions(+), 6 deletions(-)
 create mode 100644 another.txt
 delete mode 100644 test.bat

$ git pull
Already up to date.

没有出现问题。

自动化提取与构建

我用 Node.js 简单写了一个自动化脚本,能够自动下载最新版本的 MinGit-<version>-<arch>-bit.zip 并从中提取构建出四种版本的 "git-embed" 。源码和发布文件都可以在 LussacZheng/git-embed 上找到,欢迎 Star, Issue 与 PR !

参考资料

Part 1 - 嵌入式 Git

  1. Embedding Git in your Applications / 中文
  2. minimal required files to just use git-clone - Google 网上论坛
  3. Minimum set of portable Git binary files(for Windows) for clone and pull only - Stack Overflow
  4. Posts containing 'portable git' - Stack Overflow
  5. Why Is libexec so huge? · msysgit/msysgit Wiki
  6. GitHub · git-for-windows/git , msysgit/msysgit

Part 2 - Git 细节问题

  1. git - fatal: Unable to find remote helper for 'https' - Stack Overflow
  2. Cygwin git fork() error on pull - Stack Overflow
  3. git - Github: error cloning my private repository - Stack Overflow