Git submodule和Git subtree
(1)git submodule允许其他的仓库指定以commit嵌入仓库的子目录
(2)git subtree替代git submodule命令,合并子仓库到项目中的子目录。不用像submodule
那样每次子目录修改了后要init和update。万一哪次没update就直接“commit -a”或者“add .”
全commit上去就悲剧了。
(3)git subtree虽然比git submodule更好用,但是也有一定漏洞,使用时一定要特别注意。
与子模块之间的依赖
对于子模块来说,其模块版本库可以被嵌入到主版本库中去。
实现的方法是:模块版本库中的提交会以模块
子版本库Submodule,一开始以为和clone相同,其实不然
项目的版本库在某些情况下需要引用其他版本库中的文件
例如,有一套公用的版本库,可以被多个项目调用,这个公用代码分别把公用的代码拷贝到各自的项目中会造成代码冗余,求其了公共代码库的维护历史,所以用Git子模块
主版本库:main
子版本库:sub
在主版本库.git
文件下创建一个.gitmodules
文件,以便用来定义子模块版本库所在的绝对路径
[submodule "sub"]
path = sub
url = /peoject/sub
除了.gitmodules文件之外,子模块的引用信息还会被保存在.git/config文件中。该文件会在我们调用submodule init命令时完成存储,届时该命令会将从.gitmodules文件中去读的信息写入到.git/config文件中。这样就可以在git/config文件对模块版本库的路径进行本地化调整了
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
[submodule "sub"]
url = /project/sub
1.嵌入一个子模块
(1)链接目录
# git submodule add <PATH> <sub>
这样,模块版本库就会被完整的克隆到指定目录中(并且它也会创建属于他自己的.git目录)
而且,主版本库中.gitmoudules文件也将会被同步创建或更新
(2)再config文件注册子模块
# git submodule init
通过这个命令就可以完成
(3)选择子模块的版本
# cd sub
# git checkout v1.0
模块版本库工作空间最初会被设置为默认分支的HEAD。我们可以通过checkout命令选择一下相应的版本
(4)将该.gitmodules文件和子目录添加到提交中
# cd ..
# git add .gitmodules
# git add sub
当我们添加一个子模块时,主版本库中的.gitmodules文件就会随之被创建或更新,然后我们必须将其添加到提交中去。另外,子模块所在的新目录也要添加。
(5)一次新提交
# git commit -m "Submodule added"
最后,我们需要在主版本库中做一次提交
如果我们克隆了一个带子模块的版本库,就必须调用一下submodule init
命令。该命令会将.git/config
文件中各子模块的URL传送过来。之后,我们就可以调用submodule update
命令克隆版本库所在的目录了
2.克隆一个带子模块的项目
当我们克隆一个带子模块版本库时,最初在工作区中创建的只有主版本库。其子模块必须要进行显示初始化和更新。
(1)初始化子模块
# git submodule init
首先,我们必须要用submodule init 命令来完成子模块的注册
(2)更新子模块
# git submodule update
子模块在完成Git初始化配置之后,我们就可以通过submodule update命令来下载完整的子模块
git submodule status
命令查看子模块中被引用的散列值。如果存在标签的话,会以括号的形式显示在输出的结尾处。
3.使用子模块中的新版本
子版本中有新版本可用了,我们需要更新
(1)更新子模块
# cd sub
# git fetch
# git checkout v2.0
fetch命令获取模板库中的最新提交,然后用checkout制定自己所需要的提交
(2)使用新版本
# cd ..
# git add sub
# git commit -m "New version of the submodule"
如果我们想在主版本库中使用模块版本库中的某一新版本,就必须要对其进行显示修改
4.与子模块相关的工作与子模块相关的工作
在工作区中,主版本库与模板版本库中的文件都已经被修改了。随后,主版本库应该要指向模块版本库中的新提交
(1)提交并推送模块版本库中的修改
# cd sub
# git add foo.txt
# git commit -m "changed submodule"
# git push
(2)提交并推送主版本库中的修改
# cd ..
# git add bar.txt
# git add sub
# git commit -m "New version of submodule"
5.更新子模块
如果子模块的新版本是由别的开发者所记录,那么我们就应该更新自己本地的克隆版本库和工作区。
# git submodule init
# git submodule update
6.删除子模块
# git rm sub
与子树之间的依赖
1.什么是子树?
子树(subtree),既不是子模块(Submodule),也不是合并策略中的子树合并(Subtree Merge),虽然它不是Git内建的功能,但是子模块和子树合并的优点都兼而有之,并且它比子模块更简单,比子树合并更全能。
2.使用场景
例如:在项目Game中有一个子目录AI。Game和大项目AI分别是一个独立的Git项目,可以分开维护。为了避免直接复制粘贴代码,我们希望Game中的AI子目录与AI中的Git项目相关联,有3层意思。
(1)AI子目录使用AI中的Git项目来填充,内容保持一致。
(2)当AI中的Git项目代码有更新,可以拉取更新到Game项目AI子目录来。
(3)反过来,当Game项目的AI子目录有变更,还可以推送这些变更到AI中的Git项目。这时候git subtree可以轻松满足上面的需求。
(1)创建subtree
语法:
git remote add -f <子仓库名> <子仓库git地址>
git subtree add --squash --prefix=<子目录名> <子仓库名> <分支>
解释:
1.-f意思是在添加远程仓库之后,立即执行fetch
2.--squash,适用于add/pull/merge子命令。意思是subtree上面的改动合并成一次commit,这样就不用拉取子项目完整的历史记录。这样的好处是让主项目历史记录很规整,缺点是子项目更新时常常需要解决冲突。一个更好的解决方案是:单独建一个分支进行--no--squash子树更新,然后再--squash合并到主分支。每次在此分支操作前都需要先把主分支合并进来。
3.--prefix,引用库对应的本地目录,“=”也可以用空格代替
# git subtree add --prefix=sub /global-path-to/sub v2.0
# git subtree add --squash --prefix=sub /global-path-to/sub master
(2)从远程仓库更新子目录
语法:
git fetch <子仓库名> <分支>
git subtree pull --prefix=<子目录名> <子仓库名> <分支> --squash
(3)更新pull
语法:
git subtree pull --prefix=<子目录名> <子仓库名> <分支>
(4)从子目录push到远程仓库
语法:
git subtree push --prefix=<子目录名> <子仓库名> master
(5)推送到远程
git push origin <分支>
网友评论