文章目录
- 第十章 Git 补丁与离线共享(下)
- 10.4 补丁的发送
- 10.5 创建 Git 打包文件(bundles)
- 10.6 使用 Git 打包文件(bundle)
- 10.7 创建基于 tree 的存档文件
第十章 Git 补丁与离线共享(下)
本章相关主题
- 补丁的创建(见上篇)
- 从分支创建补丁(见上篇)
- 补丁的应用(见上篇)
- 补丁的发送
- 创建 Git 打包文件(bundles)
- 使用 Git 打包文件(bundle)
- 创建基于 tree 的存档文件
10.4 补丁的发送
Git 还可以通过命令 git send-email
直接已电子邮件的方式发送补丁。不过该命令需要手动配置,且相关配置严重依赖具体的邮箱和 SMTP
协议要求。相关配置信息参考:http://git-scm.com/docs/git-send-email。
这里仅供演示:
$ git clone https://github.com/PacktPublishing/Git-Version-Control-Cookbook-Second-Edition_offline-sharing.git
$ cd Git-Version-Control-Cookbook-Second-Edition_offline-sharing
$ git format-patch -1 -o latest-commit
latest-commit/0001-Calculate-pi-with-more-digits.patch
$ emailaddr=$(git config user.email)
$ git send-email --to $emailaddr --from $emailaddr latest-commit/0001-Calculate-pi-with-more-digits.patch
latest-commit/0001-Calculate-pi-with-more-digits.patch
(mbox) Adding cc: John Doe <john.doe@example.com> from line 'From: John Doe <john.doe@example.com>'OK. Log says:Server: smtp.gmail.comMAIL FROM:<john.doe@example.com>RCPT TO:<john.doe@example.com>From: john.doe@example.comTo: john.doe.example.comSubject: [PATCH] Calculate pi with more digitsDate: Mon, 14 Apr 2014 09:00:11 +0200Message-Id: <1397458811-13755-1-git-send-email-john.doe@example.com>X-Mailer: git-send-email 1.9.1 # using --cover-letter:
$ git checkout develop
Switched to branch 'develop'
Your branch is up-to-date with 'origin/develop'.
$ git send-email --to john.doe@example.com --from john.doe@example.com --cover-letter --annotate origin/master
10.5 创建 Git 打包文件(bundles)
Git 还可以通过打包文件(bundles
)共享提交历史。打包文件是可以用作远程仓库的一组 commit
,可以不包含 git
库的所有提交记录。
$ git clone https://github.com/PacktPublishing/Git-Version-Control-Cookbook-Second-Edition_offline-sharing.git offline-sharing
$ cd offline-sharing
$ git checkout master; git checkout develop; git checkout master
# create root bundle
$ git bundle create myrepo.bundle master
create myrepo.bundle master
Enumerating objects: 13, done.
Counting objects: 100% (13/13), done.
Compressing objects: 100% (12/12), done.
Total 13 (delta 1), reused 9 (delta 0), pack-reused 0
# verify bundle
$ git bundle verify myrepo.bundle
myrepo.bundle is okay
The bundle contains this ref:
937f9602dcd2236397c916d1ac764efcfa5e97cd refs/heads/master
The bundle records a complete history.
# give it a tag
$ git tag bundleForOtherRepo master
在创建的根包的基础上,再次创建同名的第二个包,会覆盖掉之前的根包文件。新的包中包含了标识标签到 develop
分支的历史记录:
$ git bundle create .\myrepo.bundle bundleForOtherRepo..develop
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Compressing objects: 100% (7/7), done.
Total 9 (delta 2), reused 9 (delta 2), pack-reused 0
$ git bundle verify myrepo.bundle
myrepo.bundle is okay
The bundle contains this ref:
0276427284e6d86aca623ec68b974b860e9c3d1b refs/heads/develop
The bundle requires this ref:
2a6f0eb9e9a9bb339aa00daa3ecd05c9a730a28d
这时可以在 gitk
查看 master
和 develop
分支:gitk master develop
小贴士
第二个包和根包重名是有其合理性的。在下一节演示中您将看到,打包文件将作为远程库关联到当前库中,其
URL
是打包文件的 文件路径。如果后续的打包文件路径不变(覆盖原名),则之后同步远程库只需执行fetch
就能轻松实现。
10.6 使用 Git 打包文件(bundle)
本节演示 git
打包文件的使用:
# Init repo
$ rm -rf offline-sharing
$ git clone https://github.com/PacktPublishing/Git-Version-Control-Cookbook-Second-Edition_offline-sharing.git
$ cd Git-Version-Control-Cookbook-Second-Edition_offline-sharing
$ git checkout master
$ git bundle create myrepo.bundle master
Enumerating objects: 13, done.
Counting objects: 100% (13/13), done.
Compressing objects: 100% (12/12), done.
Total 13 (delta 1), reused 9 (delta 0), pack-reused 0
$ git tag bundleForOtherRepo master
# Demo: create repo from bundle file
$ cd ..
$ git clone -b master Git-Version-Control-Cookbook-Second-Edition_offline-sharing/myrepo.bundle offline-other
Cloning into 'offline-other'...
Receiving objects: 100% (13/13), done.
Resolving deltas: 100% (1/1), done.
$ cd offline-other
$ git log --oneline --decorate --all
执行结果:
符合预期。接下来创建第二个打包文件,范围从标识标签到 develop
分支:
$ cd ..
$ cd Git-Version-Cookbook-Second-Edition_offline-sharing
$ git checkout develop
$ git checkout master
$ git bundle create myrepo.bundle bundleForOtherRepo..develop
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Compressing objects: 100% (7/7), done.
Total 9 (delta 2), reused 9 (delta 2), pack-reused 0
$ git bundle verify myrepo.bundle
myrepo.bundle is okay
The bundle contains this ref:
0276427284e6d86aca623ec68b974b860e9c3d1b refs/heads/develop
The bundle requires this ref:
2a6f0eb9e9a9bb339aa00daa3ecd05c9a730a28d
实测过程中发现,创建第二个打包文件需要先签出 develop
分支到本地,否则报错:
# if develop branch is not checkout locally
$ git bundle create .\myrepo.bundle bundleForOtherRepo..develop
fatal: ambiguous argument 'bundleForOtherRepo..develop': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
根据提示,新的打包文件需要一个 commit
:2a6f0eb9e9a9bb339aa00daa3ecd05c9a730a28d
。在 offline-other
文件夹中进行验证:
$ cd ..
$ cd offline-other
$ git show -s 2a6f0eb9e9a9bb339aa00daa3ecd05c9a730a28d
commit 2a6f0eb9e9a9bb339aa00daa3ecd05c9a730a28d
Author: John Doe <john.doe@example.com>
Date: Wed Apr 9 21:28:51 2014 +0200Adds checker for prime number
验证通过,说明新打包文件可以直接应用到这个库,执行 git fetch
即可:
$ git fetch
Receiving objects: 100% (9/9), done.
Resolving deltas: 100% (2/2), done.
From C:/Users/z/Desktop/Git-Version-Control-Cookbook-Second-Edition_offline-sharing/myrepo.bundle* [new branch] develop -> origin/develop
接着签出 develop 分支,此时 master 与 develop 应该与原仓库一致:
$ git checkout develop
$ gitk --all
运行结果如下:(符合预期)
小贴士
git
打包文件适用于设备间没有网络连接、或因为防火墙受限而无法使用正常共享提交历史的情况。其主要优点是每次需要更新远程时,无需将整个历史记录写入bare
库,而只需将需要同步的部分写入打包文件即可。
10.7 创建基于 tree 的存档文件
若是不考虑提交历史,怎样像 commit
提交那样,得到一个项目的目录结构快照呢?你可以忽略 .git
文件夹,从某个指定版本创建一个存档文件(archive
)。Git
有专门的命令处理类似场景,可以基于特定的版本或引用来实现。但要注意,用 Git
创建的存档文件仅包含被 Git
纳入版本管理的内容,工作区中不参与版本控制的文件或文件夹是不在该存档范围内的。
本节仍以 offline-sharing
库为例进行演示,在 master
分支的最新版本上创建存档(原书中默认为 develop
分支的说法与实测并不相符):
# Init repo
$ git clone https://github.com/PacktPublishing/Git-Version-Control-Cookbook-Second-Edition_offline-sharing.git
$ cd Git-Version-Control-Cookbook-Second-Edition_offline-sharing
# Create archive
$ git archive --prefix=offline/ -o offline.zip master
$ unzip -l offline.zip
Archive: offline.zip
937f9602dcd2236397c916d1ac764efcfa5e97cdLength Date Time Name
--------- ---------- ----- ----0 2021-01-15 15:34 offline/162 2021-01-15 15:34 offline/README.md485 2021-01-15 15:34 offline/another_pi.c672 2021-01-15 15:34 offline/math.c
--------- -------1319 4 files
# Check with git ls-tree
$ git ls-tree -l master
100644 blob c79cad47938a25888a699142ab3cdf764dc99193 162 README.md
100644 blob 86df41b3a8bbfb588e57c7b27742cf312ab3a12a 485 another_pi.c
100644 blob d393b41eb14561e583f1b049db716e35cef326c3 672 math.c
可见,存档内容与指定版本(当前 master
分支的 HEAD
)一致。
拓展
除了指定版本,还可以指定从某个子文件夹创建存档文件。例如基于 doc
分支的 Documentation
文件夹,可以创建存档如下:
$ git archive --prefix=docs/ -o docs.zip origin/doc:Documentation
$ git unzip -l docs.zip
Archive: docs.zipLength Date Time Name
--------- ---------- ----- ----0 2022-01-06 22:37 docs/99 2022-01-06 22:37 docs/README.md152 2022-01-06 22:37 docs/build.md
--------- -------251 3 files
# Check content
$ git ls-tree -l origin/doc:Documentation
100644 blob b65b4fc78c0e39b3ff8ea549b7430654d413159f 99 README.md
100644 blob f91777f3e600db73c3ee7b05ea1b7d42efde8881 152 build.md
此外,导出的存档格式也可以指定,如 tar
、tar.gz
等,通过参数 --format=<format>
指定或在 -o
参数后写明导出文件的扩展名即可。以下两个命令是等效的:
$ git archive --format=tar.gz HEAD > offline.tar.gz
$ git archive -o offline.tar.gz HEAD
如果指定的版本不是分支形式,而是一个 commit
、tag
、或 tree
的 ID,则生成的存档文件略有差别。指定 commit
或 tag
时,导出为 tar
格式的存档文件会将该 ID 存到一个全局的 pax header
头;而格式为 zip
时,该 ID 会以文件注释的形式呈现。若指定的是 tree
的 ID,存档文件则不会保留任何附加信息。这可以在刚刚演示的两种情况得到验证。打开 offline.zip
文件,可以看到 master
的 HEAD
头对应的 SHA-1
(937f9602dcd2236397c916d1ac764efcfa5e97cd
)出现在了文件注释位置:
另一方面,以子文件夹 Documentation
导出的存档文件则没有任何显示: