如何把一个工程中的某个目录添加为git submodule

举例:我的工程叫My,目录树如下

My
|-- My
|   |-- Support
|   |-- main.m
|   |-- images
|   |-- My-Prefix.pch
|   |-- My-Info.plist
|   |-- MyAppDelegate.h
|   |-- MyAppDelegate.m
|
|-- My.xcodeproj

我希望把项目AFNetworking加成Submodule,他的目录树如下

AFNetworking
|-- AFNetworking // 这个是真正需要的目录
|-- AFNetworking.xcworkspace
|-- Example
|-- .gitignore
|-- AFNetworking.podspec
|-- CHANGES
|-- LICENSE
|-- README.md

我要把AFNetworking加成submodule

git submodule add https://github.com/AFNetworking/AFNetworking.git My/Support/AFNetworking

最终My的目录结构

My
|-- My
|   |-- Support
|   |   |-- AFNetworking
|   |       |-- AFNetworking // 这个是真正需要的目录
|   |       |-- AFNetworking.xcworkspace
|   |       |-- Example
|   |       |-- .gitignore
|   |       |-- AFNetworking.podspec
|   |       |-- CHANGES
|   |       |-- LICENSE
|   |       |-- README.md
|   |    
|   |-- main.m
|   |-- images
|   |-- My-Prefix.pch
|   |-- My-Info.plist
|   |-- MyAppDelegate.h
|   |-- MyAppDelegate.m
|
|-- My.xcodeproj

我希望得到的目录结构是

My
|-- My
|   |-- Support
|   |   |-- AFNetworking // 这个是真正需要的目录
|   |
|   |-- main.m
|   |-- images
|   |-- My-Prefix.pch
|   |-- My-Info.plist
|   |-- MyAppDelegate.h
|   |-- MyAppDelegate.m
|
|-- My.xcodeproj

我通过在子模块目录执行这个命令,达到了效果

git filter-branch -f --subdirectory-filter AFNetworking/AFNetworking -- --all

然后

git filter-branch -f --index-filter "git rm -r -f --cached --ignore-unmatch AFNetworking/AFNetworking" --prune-empty

然后回到父仓库commit并push
看起来一切完美了,但是我重新在clone的时候
这个Submodule的状态是挂的。。。完全clone不出来,AFNetworking只是个目录,没有文件内容
我用SourceTree打开这个工程,然后看通过submodule的方式打开AFNetworking,reset一下,目录结构就回到运行 filter-branch 命令之前的样子了
也就是说,这个效果只有我一个人在运行了 filter-branch 之后看的到,有没有什么办法,可以让大家都看到呢?
另外,我还不知道这样做了以后,如果submodule有更新,能否正常。

阅读 25.9k
3 个回答

git 的 submodule 方式不会向仓库添加实际的的内容的,只会通过 .gitmodules 文件保留相应的子模块的哈希值。

由于你要真正要用的代码处于一个子目录中,我的方案是你先把这个子目录提取成一个单独的仓库(可以使用 git-subtree.sh 这个脚本),然后再添加这个仓库为 submodule(或者直接使用 git-subtree.sh 把实际的代码集成到你的项目,这样别人克隆就不需要更新 submodule 了)。这样做的缺点就是每当上游有更新,就需要对 submodule 的仓库做相应更新。

另外:git-subtree.sh 已经合并入 git 了,可能并不在 PATH 中,不能直接执行,不过应该在 git 的安装中的。

另一个思路:

建立 bundles 目录,添加原仓库为 submodule 到此,然后对需要的子目录做相对路径软链接,git 能够正确处理软链接。这可能是比较好的一个办法了,不需要额外维护同上游的同步。

-----------

你在子模块目录中进行的 subdirectory-filter 已经是 git-subree.sh 的 split 操作了,这个时候该仓库已经和 orgin 完全不同了,等于重新建立了以该 subdirectory 为根的一个仓库,这个仓库中的对象只在你的本地,并不包含在 origin 的仓库中,所以最后才会无效的。

把一个仓库的里的子目录作为你的submodule这样的方式是不可以的。git submodule只支持整个仓库。

我发现很多依赖了submodule的xcode project都不会把submodule的project给去掉的。因为他们的是按照静态lib来依赖的,编译时会按照submodule的project先编译成lib.a文件,然后link到你的项目中。如果把submodule的project文件去掉,那么编译时,xcode会把submodule的source当做同一个项目来处理。先把*.m文件编译出来,然后再link。

楼上说得git-subtree.sh可能是个办法。不过我没尝试过。

最后还是建议你尝试cocoapods,嘿嘿。

hi gaosboy, 我通过git submodule将子仓库放到多层目录结构中报错了,报错截图如下,想问问你是怎么实现的?
clipboard.png

我在网上也找了答案, 截图如下
clipboard.png

 git rm -r src/routes清除同名模块
git submodule add http://quan.wang@stash.weimob.com/scm/h/jingxuan-manage-submodule.git src/routes

此时出现了新的报错, 截图如下

clipboard.png

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏