Git Submodule入门与实践

子模块初步

引用一段《Git权威指南》的话:
项目的版本库在某些情况虾需要引用其他版本库中的文件,例如公司积累了一套常用的函数库,被多个项目调用,显然这个函数库的代码不能直接放到某个项目的代码中,而是要独立为一个代码库,那么其他项目要调用公共函数库该如何处理呢?分别把公共函数库的文件拷贝到各自的项目中会造成冗余,丢弃了公共函数库的维护历史,这显然不是好的方法。

为现有的仓库添加submodule,以第三方库CodeMirror为示例,在当前仓库下执行:

查看当前仓库的状态,注意到:submodule 和 .gitmodules两个文件已经自动被staged。

git status

其中.gitmodules保存了项目 URL 和你拉取到的本地子目录。如果有多个子module,则该文件会记录多个条目:

虽然 CodeMirror 是工作目录中的一个子目录,但 Git 还是会将它视作一个子模块。当你不在那个目录中时,Git 并不会跟踪它的内容, 而是将它看作该仓库中的一个特殊提交。

当你提交时,会看到类似下面的信息:

注意 CodeMirror 记录的 160000 模式。 这是 Git 中的一种特殊模式,它本质上意味着你是将一次提交记作一项目录记录的,而非将它记录成一个子目录或者一个文件。

最后推送至远端

git push -u origin master

克隆一个带子模块的项目

你将得到了包含子项目的目录,但里面没有文件:

git clone http://git.xhuabu.com/chenrunfa/UI-module.git

需要通过两个命令来初始化:git submodule init来初始化你的本地配置文件,git submodule update来从那个项目拉取所有数据并检出你上层项目里所列的合适的提交:

或者将这两个命令写成一句话:git submodule update --init --recursive

但最快的方法是,克隆时连同所有子项目一起拉下来:

git clone --recursive http://git.xhuabu.com/chenrunfa/UI-module.git

删除子模块

删除子模块相对比较麻烦一些step by:

  1. 删除git cache和物理文件夹 git rm -r --cached libs/
  2. 删除.gitmodules rm .gitmodules,如果只是删除其中一个module,响应删除.gitmodules中对应条目即可
  3. 删除.git/config的submodule配置 源文件
  4. 提交更改

子模块深入

场景:某个工作中的项目需要包含并使用另一个项目。 也许是第三方库,或者你
独立开发的,用于多个父项目的库。现在你想要把它们当做两个独立的项目,同时又想在 一个项目中使用另一个。

  • 克隆一个带有子模块的工程git submodule update --init --recursive

  • 直接在主仓库里抓取与合并子模块

    • git submodule update --remote
  • 或者只更新指定的子模块

    • 进入子模块目录
    • git fetch
    • git merge origin/master
  • 在子模块上工作

    当我们运行 git submodule update 从子模块仓库中抓取修改时,Git 将会获得这些改动并 更新子目录中的文件,但是会将子仓库留在一个称作 “游离的 HEAD” 的状态。 这意味着没有本 地工作分支(例如 “master”)跟踪改动。 所以你做的任何改动都不会被跟踪。

 git checkout master                     进入子模块并检出相应的工作分支
 git submodule update --remote            从上游拉取数据
 git submodule update --remote --merge     从上游拉取数据并合并
  • 发布子模块改动

如果我们在主项目中提交并推送但并不推送子模块上的改动,其他尝试检出我们修改的人会遇到 麻烦,因为他们无法得到依赖的子模块改动。 那些改动只存在于我们本地的拷贝中。

为了确保这不会发生,你可以让 Git 在推送到主项目前检查所有子模块是否已推送。 git push 命令接受可以设置为 check 或on-demand 的 –recurse-submodules 参数。 如果任何提交的子模块改动没有推送那么 check 选项会直接使push 操作失败。

  • 提交主项目时自动检测子模块是否有未提交的改动
git push --recurse-submodules=check
  • 提交主项目时,尝试自动推送一改动的子模块
git push --recurse-submodules=on-demand

案例分析


案例1:当前企业正在开发Project1项目,Project1中除了自身源代码外还包含了一个名为CommonLib的submodule,此时,项目开发中途加入了两位新的开发人员(员工A和员工B),参与开发最首要的就是先搭建环境并获取当前项目的代码,才能投入开发状态;

A和B分别执行:git clone --recursive http://git.xhuabu.com/chenrunfa/UI-module.git 快速获取含有子模块的代码仓库。


案例2:在加入Project1项目的开发后,某一天,新员工A发现了CommonLib的代码中存在一个BUG或者是发现一个新的功能在其他项目也需要被用到,此时需要改动CommonLib中的源代码。

A在修复了BUG之后,如果按照直接执行在Project1目录下执行git commit –am “相关描述”进行提交,对submodule发生的改变是没有任何作用的,因为这种提交方式只是提交当前Project1主工程的修改,对于submodule发生的改变不会进行提交。

正确的提交方式先进入CommonLib子模块的目录

cd 子模块目录
git commit –am “相关描述”(如果增删了文件,需要先做git add .操作)
git rebase remotes/origin/master (同步服务器上的子模块代码)
git push(提交子模块到远程库)
cd 主工程目录
git add 子模块目录(将子模块发生修改告诉你的主工程,这样他才能进行跟踪)
git commit –am “相关描述”
git push (提交主工程到远程库)完成以上流程的操作,才算正确的提交了子模块的修改,并让主工程跟踪跟新子模块。

案例3:新员工A在更新的CommonLib的子模块后,其他一起开发Project1项目的人员(包括了新员工B)都都需要同步更新CommonLib中的代码。

此时新员工B需要执行如下的几个操作来:

git pull (在主工程目录下同步更新代码
git status(查看submodule是否发生了修改)
git submodule update(如果子模块发生修改,需要执行此操作进行更新)
如果子模块下还包含着子模块,最后一句的更新操作可以换成如下的命令:
git submodule foreach git submodule update

实际上,submodule项目和它的父项目本质上是2个独立的git仓库。只是父项目存储了它依赖的submodule项目的版本号信息而已。如果其他同事更新了submodule,然后更新了父项目中依赖的版本号。你需要在git pull之后,调用 git submodule update来更新submodule信息。
有些时候你需要对submodule做一些修改,很常见的做法就是切到submodule的目录,然后做修改,然后commit和push。但是默认git submodule update并不会将submodule切到任何branch,所以,默认下submodule的HEAD是处于游离状态的(‘detached HEAD’state)。所以在修改前,记得一定要用git checkout master将当前的submodule分支切换到master,然后才能做修改和提交。

如果你不慎忘记切换到master分支,又做了提交,可以用cherry-pick命令挽救。具体做法如下:

git log (获取当前在游离分支提交的commitid)
git checkout master(将HEAD从游离状态切换到 master 分支)
git cherry-pick 游离分支上提交的commitID (将提交从游离分支放到master分支上)
git push (将更新提交到远程版本库中)

以上案例来自:http://blog.csdn.net/d_clock/article/details/43730449

补充

iOS项目中通过submodule管理library的例子:
http://blog.changyy.org/2012/12/ios-xcode-subprojects-git-submodule.html

git submodule搭配上Android studio的modules來管理source:
https://erttyy8821.gitbooks.io/android_memo/content/chapter1/SubmoduleAndModules.html

git submodule详细使用说明:
https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97

你可能感兴趣的:(git)