- 23.4 隐性子模组
- On branch master
- Untracked files:
- (use "git add<file>…" to include in what will be committed)
- others/
- On branch master
- Changes to be committed:
- (use "git reset HEAD<file>…" to unstage)
- new file:others
- Changed but not updated:
- (use "git add<file>…" to update what will be committed)
- (use "git checkout—<file>…" to discard changes in working directory)
- (commit or discard the untracked or modified content in submodules)
- modified:others(untracked content)
- On branch master
- Changes to be committed:
- (use "git reset HEAD<file>…" to unstage)
- deleted:others
- Untracked files:
- (use "git add<file>…" to include in what will be committed)
- others/
- On branch master
- Changes to be committed:
- (use "git reset HEAD<file>…" to unstage)
- deleted:others
- new file:others/newfile
23.4 隐性子模组
我在开发备份工具Gistore[1]时遇到一个棘手的问题,就是隐性子模组的问题。Gistore备份工具的原理是将要备份的目录都挂载(mount)在工作区中,然后执行git add。但是如果有某个目录已经被Git化了,就只会以子模组的方式将该目录添加进来,而不会添加该目录下的文件。对于一个备份工具来说,这就意味着备份没有成功。具体操作过程如下:
(1)例如当前super版本库下有两个子模组:
$cd/path/to/my/workspace/super-clone/
$git submodule status
126b18153583d9bee4562f9af6b9706d2e104016 lib/lib_a(remotes/origin/HEAD)
3b52a710068edc070e3a386a6efcbdf28bf1bed5 lib/lib_b(heads/master)
(2)然后创建一个新目录others,并把该目录用Git初始化,并做一次空的提交。
$mkdir others
$cd others
$git init
$git commit—allow-empty-m initial
[master(root-commit)90364e1]initial
(3)在others目录下创建一个文件newfile。
$date>newfile
(4)回到上一级目录执行git status,看到有一个others目录没有加入版本库控制,这很自然。
$cd..
$git status
On branch master
Untracked files:
(use "git add<file>…" to include in what will be committed)
#
others/
nothing added to commit but untracked files present(use "git add" to track)
(5)但是如果对others目录执行git add后,会发现奇怪的状态。
$git add others
$git status
On branch master
Changes to be committed:
(use "git reset HEAD<file>…" to unstage)
#
new file:others
#
Changed but not updated:
(use "git add<file>…" to update what will be committed)
(use "git checkout—<file>…" to discard changes in working directory)
(commit or discard the untracked or modified content in submodules)
#
modified:others(untracked content)
#
(6)看看others目录的添加方式,就会发现others目录以gitlink的方式添加到版本库中,而没有把该目录下的文件添加到版本库中。
$git diff—cached
diff—git a/others b/others
new file mode 160000
index 0000000..90364e1
—-/dev/null
+++b/others
@@-0,0+1@@
+Subproject commit 90364e1331abc29cc63e994b4d2cfbf7c485e4ad
之所以上面的步骤(5)运行git status命令时others出现了两次,就是因为目录others被当作子模组添加到了父版本库中,而且由于others版本库本身“不干净”,存在尚未加入版本控制的文件,所以又在状态输出中显示了子模组包含改动的提示信息。
接下来执行提交,将others目录提交到版本库中。然后当执行git submoudle status命令时会报错。因为others作为子模组没有在.gitmodules文件中注册。
$git commit-m "add others as submodule."
$git submodule status
126b18153583d9bee4562f9af6b9706d2e104016 lib/lib_a(remotes/origin/HEAD)
3b52a710068edc070e3a386a6efcbdf28bf1bed5 lib/lib_b(heads/master)
No submodule mapping found in.gitmodules for path 'others'
那么如何在不破坏others版本库的前提下,把others目录下的文件加入版本库呢?即避免others以子模组形式添加入库,具体操作过程如下。
(1)先删除以gitlink形式入库的others子模组。
$git rm—cached others
rm 'others'
(2)查看当前状态。
$git status
On branch master
Changes to be committed:
(use "git reset HEAD<file>…" to unstage)
#
deleted:others
#
Untracked files:
(use "git add<file>…" to include in what will be committed)
#
others/
(3)重新添加others目录,注意目录后面的斜线(即路径分隔符)非常重要。
$git add others/
(4)再次查看状态,看到others下的文件被添加到super版本库中。
$git status
On branch master
Changes to be committed:
(use "git reset HEAD<file>…" to unstage)
#
deleted:others
new file:others/newfile
#
(5)执行提交。
$git commit-m "add contents in others/."
[master 1e0c418]add contents in others/.
2 files changed,1 insertions(+),1 deletions(-)
delete mode 160000 others
create mode 100644 others/newfile
在上面的操作过程中,首先删除了库中的others子模组(使用—cached参数执行删除);然后为了添加others目录下的文件使用了"others/"(注意others后面的路径分割符“/”)。现在查看一下子模组的状态,会看到只显示出了之前的两个子模组。
$git submodule status
126b18153583d9bee4562f9af6b9706d2e104016 lib/lib_a(remotes/origin/HEAD)
3b52a710068edc070e3a386a6efcbdf28bf1bed5 lib/lib_b(heads/master)
[1]参见本书第7篇“第37章 Gistore”。