- 24.2 子目录方式合并外部版本库
- On branch master
- Changes to be committed:
- (use "git reset HEAD<file>…" to unstage)
- new file:lib/Makefile
- new file:lib/version
- Changed but not updated:
- (use "git add/rm<file>…" to update what will be committed)
- (use "git checkout—<file>…" to discard changes in working directory)
- deleted:lib/Makefile
- deleted:lib/version
- On branch master
- Changes to be committed:
- (use "git reset HEAD<file>…" to unstage)
- new file:lib/Makefile
- new file:lib/version
24.2 子目录方式合并外部版本库
下面就用Git的底层命令git read-tree、git write-tree和git commit-tree子命令,实现将util-branch分支所包含的util.git版本库的目录树以子目录(lib/)的形式添加到master分支中。
先来看看util-branch分支当前的最新提交,记住最新提交所指向的目录树(tree),即tree id:0c743e4。
$git cat-file-p util-branch
tree 0c743e49e11019678c8b345e667504cb789431ae
parent f21f9c10cc248a4a28bf7790414baba483f1ec15
author Jiang Xin<jiangxin@ossxp.com>1288494998+0800
committer Jiang Xin<jiangxin@ossxp.com>1288494998+0800
util v2.0->v3.0
查看tree 0c743e4所包含的内容,会看到两个文件:Makefile和version。
$git cat-file-p 0c743e4
100644 blob 07263ff95b4c94275f4b4735e26ea63b57b3c9e3 Makefile
100644 blob bebe6b10eb9622597dd2b641efe8365c3638004e version
切换到master分支,以如下方式调用git read-tree将util-branch分支的目录树读取到当前分支lib目录下,具体操作过程如下。
(1)切换到master分支。
$git checkout master
(2)执行git read-tree命令,将分支util-branch读取到当前分支的一个子目录下。
$git read-tree—prefix=lib util-branch
(3)调用git read-tree只是更新了暂存区,所以查看工作区状态会看到工作区中还不存在lib目录下的两个文件。
$git status
On branch master
Changes to be committed:
(use "git reset HEAD<file>…" to unstage)
#
new file:lib/Makefile
new file:lib/version
#
Changed but not updated:
(use "git add/rm<file>…" to update what will be committed)
(use "git checkout—<file>…" to discard changes in working directory)
#
deleted:lib/Makefile
deleted:lib/version
#
(4)执行检出命令,将lib目录下的文件更新出来。
$git checkout—lib
(5)再次查看状态,会看到前面执行的git read-tree命令添加到了暂存区的文件中。
$git status
On branch master
Changes to be committed:
(use "git reset HEAD<file>…" to unstage)
#
new file:lib/Makefile
new file:lib/version
#
现在还不能忙着提交,因为如果现在进行提交就体现不出两个分支的合并关系。需要使用Git底层的命令进行数据提交,具体操作过程如下。
(1)调用git write-tree将暂存区的目录树保存下来。
要记住调用git write-tree后形成的新的tree-id:2153518。
$git write-tree
2153518409d218609af40babededec6e8ef51616
(2)执行git cat-file命令显示这棵树的内容,会注意到其中lib目录的tree-id和之前查看过的util-branch分支最新的提交对应的tree-id一样都是0c743e4。
$git cat-file-p 2153518409d218609af40babededec6e8ef51616
100644 blob 07263ff95b4c94275f4b4735e26ea63b57b3c9e3 Makefile
040000 tree 0c743e49e11019678c8b345e667504cb789431ae lib
100644 blob 638c7b7c6bdbde1d29e0b55b165f755c8c4332b5
version
(3)要手工创建一个合并提交,即新的提交要有两个父提交。这两个父提交分别是master分支和util-branch分支的最新提交。用下面的命令显示两个提交的提交ID,并记下这两个提交ID。
$git rev-parse HEAD
911b1af2e0c95a2fc1306b8dea707064d5386c2e
$git rev-parse util-branch
12408a149bfa78a4c2d4011f884aa2adb04f0934
(4)执行git commit-tree命令手动创建提交。新提交的目录树来自上面的git write-tree产生的目录树(tree-id为2153518),而新提交(合并提交)的两个父提交直接用上面git rev-parse显示的两个提交ID表示。
$echo "subtree merge"|\
git commit-tree 2153518409d218609af40babededec6e8ef51616\
-p 911b1af2e0c95a2fc1306b8dea707064d5386c2e\
-p 12408a149bfa78a4c2d4011f884aa2adb04f0934
62ae6cc3f9280418bdb0fcf6c1e678905b1fe690
(5)执行git commit-tree命令的输出是提交之后产生的新提交的提交ID。需要把当前的master分支重置到此提交ID。
$git reset 62ae6cc3f9280418bdb0fcf6c1e678905b1fe690
(6)查看一下提交日志及分支图,可以看到通过复杂的git read-tree、git write-tree和git commit-tree命令制造的合并提交,的确将两个不同的版本库合并到一起了。
$git log—graph—pretty=oneline
*62ae6cc3f9280418bdb0fcf6c1e678905b1fe690 subtree merge
|\
|*12408a149bfa78a4c2d4011f884aa2adb04f0934 util v2.0->v3.0
|*f21f9c10cc248a4a28bf7790414baba483f1ec15 util v1.0->v2.0
|*76db0ad729db9fdc5be043f3b4ed94ddc945cd7f util v1.0
*911b1af2e0c95a2fc1306b8dea707064d5386c2e main v2010.1
(7)看看现在的master分支。
$git cat-file-p HEAD
tree 2153518409d218609af40babededec6e8ef51616
parent 911b1af2e0c95a2fc1306b8dea707064d5386c2e
parent 12408a149bfa78a4c2d4011f884aa2adb04f0934
author Jiang Xin<jiangxin@ossxp.com>1288498186+0800
committer Jiang Xin<jiangxin@ossxp.com>1288498186+0800
subtree merge
(8)看看目录树。
$git cat-file-p 2153518409d218609af40babededec6e8ef51616
100644 blob 07263ff95b4c94275f4b4735e26ea63b57b3c9e3 Makefile
040000 tree 0c743e49e11019678c8b345e667504cb789431ae lib
100644 blob 638c7b7c6bdbde1d29e0b55b165f755c8c4332b5 version
整个过程非常繁琐,但是不要太过担心,只需要对原理了解清楚就可以了,因为在后面会介绍一个Git插件,它封装了复杂的子树合并操作。