git subtree有效管理公共第三方lib
如果你的项目中有很多第三方的lib,你希望使用它,并且也希望可能对该lib做修改并且贡献到原始的项目中去,或者你的项目希望模块化,分为几个repo单独维护,那么git subtree就是一个选择。git subtree管理的子项目在父项目中作为一个完整的代码copy存在,并不包含历史信息。综合考虑git subtree和git submodule的优缺点,一个可行的管理策略是:使用git subtree对父项目(在该父项目中可以临时将子项目文件夹加入到tracking中)做split,将需要单独存在的目录形成一个子项目,并且push出来。随后再父项目的开发中,将子项目目录加入git ignore中,不做版本跟踪,子项目目录以另一个git repo存在(git clone子项目)。所有本地副项目中的修改如果需要分享的话,只在子项目repo中提交并且push,其他成员只需pull这个子项目repo。这个策略是一个折中。
git subtree是附属于git的附加工具,默认情况下并不会安装。https://github.com/git/git/tree/master/contrib/subtree。注意新版本的git中已经默认包含了subtree这个子命令
#
git clone https://github.com/git
# cd git# make prefix=/usr/local/git install
# echo "export PATH=$PATH:/usr/local/git/bin" >> /etc/bashrc
# source /etc/bashrc
# cd contrib/subtree
# makeprefix=/usr/local/git/bin
# make
prefix=/usr/local/git/bin install
# make
prefix=/usr/local/git/bin install-doc
# cp git-subtree
/usr/local/git/bin :一旦将git-bustree copy到git/bin目录下,执行git subtree 命令时,git就可以查找并且调用到这个subtree子命令了!
就ok了!
在本文中,我们假设我们工作在subtree-p这个项目中(放在github上的一个repo),而在该项目中,我们需要subtree-sub这个子模块(或者说是Lib).
当前我们的subtree-p项目中,没有引入任何subtree-sub这个模块,现在我们通过以下命令来实现:
(master)$ git remote add subtree-sub-remote https://github.com/cnweibo/subtree-sub.git
(master)$ git remote -v
origin https://github.com/cnweibo/subtree-p.git (fetch)
origin https://github.com/cnweibo/subtree-p.git (push)
subtree-sub-remote https://github.com/cnweibo/subtree-sub.git (fetch)
subtree-sub-remote https://github.com/cnweibo/subtree-sub.git (push)
(master)$ pwd
/home/cabox/workspace/subtreetest/subtree-p
(master)$ ls
README.md
(master)$ git subtree add --prefix=mysubtree subtree-sub-remote master
git fetch subtree-sub-remote master
warning: no common commits
remote: Counting objects: , done.
remote: Total (delta ), reused (delta ), pack-reused
Unpacking objects: % (/), done.
From https://github.com/cnweibo/subtree-sub
* branch master -> FETCH_HEAD
* [new branch] master -> subtree-sub-remote/master
Added dir 'mysubtree'
(master)$ ls
README.md mysubtree
(master)$ ls -la mysubtree/
total
drwxrwxr-x cabox cabox May : .
drwxrwxr-x cabox cabox May : ..
-rw-rw-r-- cabox cabox May : README.md
上面的一系列命令中,首先在subtree-p项目目录中引入了subtree-sub这个子项目,它存放在目录mysubtree中,和我们的subtree-sub-remote这个remote相对应。这时,subtree-p项目由于增加了新的目录(subtree-sub子项目repo),因此需要commit和push.
注意:在mysubtree这个子目录中是没有任何.git文件的,它实际上是subtree-sub这个子项目repo的纯代码copy!! git subtree add命令本身不会像git submodule add一样添加任何meta data@!!
(master)$ git s
On branch master
Your branch is ahead of 'origin/master' by commits.
(use "git push" to publish your local commits)
nothing to commit, working directory clean
(master)$ git push
Username for 'https://github.com': kidsit
Password for 'https://kidsit@github.com':
Counting objects: , done.
Delta compression using up to threads.
Compressing objects: % (/), done.
Writing objects: % (/), bytes | bytes/s, done.
Total (delta ), reused (delta )
To https://github.com/cnweibo/subtree-p.git
67da25d..c1e6018 master -> master
这时,我们查看在github上的subtree-p repo,你就可以看到这个父项目已经引入了mysubtree(代表了subtree-sub repo!)
现在我们在parent项目中对子项目做修改并且commit, push:
(master)$ echo "kidsit add subfile1 within parent" >subfile1
(master)*$ git s
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
(use "git add <file>..." to include in what will be committed) subfile1 nothing added to commit but untracked files present (use "git add" to track)
(master)*$ git a .
(master)*$ git ci "kidsit add subfile1 within parent"
[master ed30a68] kidsit add subfile1 within parent
file changed, insertion(+)
create mode mysubtree/subfile1
(master)$ git s
On branch master
Your branch is ahead of 'origin/master' by commit.
(use "git push" to publish your local commits)
nothing to commit, working directory clean
(master)$ git push
Username for 'https://github.com': kidsit
Password for 'https://kidsit@github.com':
Counting objects: , done.
Delta compression using up to threads.
Compressing objects: % (/), done.
Writing objects: % (/), bytes | bytes/s, done.
Total (delta ), reused (delta )
To https://github.com/cnweibo/subtree-p.git
c1e6018..ed30a68 master -> master
(master)$
这时我们再查看github上的subtree-p我们就能看到我们对子项目的新的改动了:
我们来继续模拟代码开发过程:修改subtree-p和subtree-sub后,统一一次性做一个提交:
(master)$ echo "kidsit change README for p" >README.md
(master)*$ echo "kidsit add new subfileNew2 " >mysubtree/subfileNew2
(master)*$ git s
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory) modified: README.md Untracked files:
(use "git add <file>..." to include in what will be committed) mysubtree/subfileNew2 no changes added to commit (use "git add" and/or "git commit -a")
(master)*$ git a .
(master)*$ git ci "kidsit change p and s in ONE commit"
[master a27d335] kidsit change p and s in ONE commit
files changed, insertions(+), deletions(-)
create mode mysubtree/subfileNew2
(master)$ git push
Username for 'https://github.com': kidsit
Password for 'https://kidsit@github.com':
Counting objects: , done.
Delta compression using up to threads.
Compressing objects: % (/), done.
Writing objects: % (/), bytes | bytes/s, done.
Total (delta ), reused (delta )
To https://github.com/cnweibo/subtree-p.git
ed30a68..a27d335 master -> master
(master)$
这时,我们要注意,我们再subtree-p项目中对父项目和子项目分别都做了修改,但是子项目本身的repo还没有做过任何更新,它根本不知道你曾经做过修改,这时,如果你希望将你对子项目的修改贡献出来,可以执行git subtree push命令
(master)$ git push
Username for 'https://github.com': kidsit
Password for 'https://kidsit@github.com':
Counting objects: , done.
Delta compression using up to threads.
Compressing objects: % (/), done.
Writing objects: % (/), bytes | bytes/s, done.
Total (delta ), reused (delta )
To https://github.com/cnweibo/subtree-p.git
ed30a68..a27d335 master -> master
(master)$ git subtree push --prefix=mysubtree/ subtree-sub-remote master
git push using: subtree-sub-remote master
Username for 'https://github.com': kidsit
Password for 'https://kidsit@github.com':
Counting objects: , done.
Delta compression using up to threads.
Compressing objects: % (/), done.
Writing objects: % (/), bytes | bytes/s, done.
Total (delta ), reused (delta )
To https://github.com/cnweibo/subtree-sub.git
9a0ef93..001c5d8 001c5d86c4da43ab676aaeb49763d5353353159f -> master
上面我们分别对subtree-p这个父项目和subtree-sub这个子项目分别作了push操作分享(一般来说对子项目push是非常少见的动作,因为我们更多的是拿别人的lib来用而不是开发),这时如果我们去看github上的两个项目repo的commit历史,你会发现两个repo上都有了同一个commit!!
正因为如此,我们最好是将父项目和子项目分别做commit,不要混淆在一起!这样做的好处是git subtree push时,git会自动将对父项目和子项目的commit区分清楚的,对父项目的修改不会出现在子项目repo修改历史中!
现在,我们假设另外一个人对subtree-sub这个repo独立做了新的开发,有了一个commit,但是我们的subtree-p项目实际上对此毫不知情,我们怎么能够获取别人对我们用到的子项目lib来更新呢?
在父项目目录中执行git subtree pull命令:
(master)$ git subtree pull --prefix=mysubtree -squash subtree-sub-remote master
You need to run this command from the toplevel of the working tree.
(master)$ kidsit
-bash: kidsit: command not found
(master)$ pwd
/home/cabox/workspace/subtreetest/subtree-p/mysubtree
(master)$ cd ..
(master)$ ls
README.md mysubtree
(master)$ pwd
/home/cabox/workspace/subtreetest/subtree-p
(master)$ git subtree pull --prefix=mysubtree subtree-sub-remote master
remote: Counting objects: , done.
remote: Compressing objects: % (/), done.
remote: Total (delta ), reused (delta ), pack-reused
Unpacking objects: % (/), done.
From https://github.com/cnweibo/subtree-sub
* branch master -> FETCH_HEAD
001c5d8..55689fc master -> subtree-sub-remote/master
Merge made by the 'recursive' strategy.
mysubtree/standardaloneChangeInsubtreesubRepo | +
file changed, insertion(+)
create mode mysubtree/standardaloneChangeInsubtreesubRepo
(master)$ git lg
* 4d2a47a (HEAD -> master) Merge commit '55689fc679ec0eeaf0a7853cd348309dad99fb96' from cnweibo update as
standard dev
|\
| * 55689fc (subtree-sub-remote/master) new content as a standard repo dev env for subtree-sub by cnweibo
| * 001c5d8 kidsit change p and s in ONE commit
| * ef33027 kidsit add subfile1 within parent
* | a27d335 (origin/master, origin/HEAD) kidsit change p and s in ONE commit
* | ed30a68 kidsit add subfile1 within parent
* | c1e6018 Add 'mysubtree/' from commit '9a0ef93b82b73fee89dd3d5123d441680c2a7e40'
|\ \
| |/
| * 9a0ef93 Initial commit
* 67da25d p
* f05da04 Create README.md
(master)$ ls
.git/ README.md mysubtree/
(master)$ ls mysubtree/
README.md subfile1
standardaloneChangeInsubtreesubRepo subfileNew2
(master)$ ls mysubtree/
README.md standardaloneChangeInsubtreesubRepo subfile1 subfileNew2
(master)$ git push
Username for 'https://github.com': kidsit
Password for 'https://kidsit@github.com':
Counting objects: , done.
Delta compression using up to threads.
Compressing objects: % (/), done.
Writing objects: % (/), 1.06 KiB | bytes/s, done.
Total (delta ), reused (delta )
To https://github.com/cnweibo/subtree-p.git
a27d335..4d2a47a master -> master
(master)$
上述命令主要是在subtree-p项目中pull别的独立项目对subtree-sub子模块的贡献,随后git push到主项目的repo中独立引用那一份修改。
接下来,我们来看新的项目成员进到我们的subtree-p项目中,他又该如何呢?
他首先需要做的是git clone yourParentRep, 随后git rm -r subModule, git add ,git commit.这时他的working directory中不再含有subModule的代码,他需要做的是手工创建git remote add --prefix=submodDirectory submodRemote master/v1.0,注意:在这里可以指定一个tag来选择相应的历史版本!!! git subtree add submodRemote xxxx.git master获取subrep代码到你的submodDirectory目录,这样他自己clone的repo就有了和submodRepo的联系了,他也可以对父项目和子项目来做贡献了。
请参考: https://lostechies.com/johnteague/2014/04/04/using-git-subtrees-to-split-a-repository/
git subtree方式管理的parent项目最终是包含所有子模块的完整代码的(可以不含子模块的历史),同时支持对子项目的contribute。
在一个前台可能被share,后台可能从一个换成另外一个,这样的场景就比较适合使用subtree来管理。
接下来我们再看另外一种情况: 在一个项目中,当我们完整做完稳定版本后,我们希望将public前端拿出来作为一个独立的repo来管理,这样前端和后端完全可以独立开发,要实现这个,就需要使用git subtree split命令了:
(master)$ ls
README.md mysubtree
(master)$ git subtree split --prefix=mysubtree -b splittedbranch
Created branch 'splittedbranch'
55689fc679ec0eeaf0a7853cd348309dad99fb96
(master)$ git s
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
(master)$ git branch -a
* master
splittedbranch
remotes/origin/HEAD -> origin/master
remotes/origin/master
(master)$ ls
README.md mysubtree
(master)$ git remote add splittedRemote https://github.com/cnweibo/splitted.git
(master)$ git checkout splittedbranch
Switched to branch 'splittedbranch'
(splittedbranch)$ ls
README.md standardaloneChangeInsubtreesubRepo subfile1 subfileNew2
(splittedbranch)$ pwd
/home/cabox/workspace/subtreesplit/superrepo
(splittedbranch)$ ls
README.md standardaloneChangeInsubtreesubRepo subfile1 subfileNew2
(splittedbranch)$ git remote -v
origin https://github.com/cnweibo/subtree-p.git (fetch)
origin https://github.com/cnweibo/subtree-p.git (push)
splittedRemote https://github.com/cnweibo/splitted.git (fetch)
splittedRemote https://github.com/cnweibo/splitted.git (push)
(splittedbranch)$ git push splittedRemote splittedbranch:master
Username for 'https://github.com': kidsit
Password for 'https://kidsit@github.com':
Counting objects: , done.
Delta compression using up to threads.
Compressing objects: % (/), done.
Writing objects: % (/), 1.43 KiB | bytes/s, done.
Total (delta ), reused (delta )
To https://github.com/cnweibo/splitted.git
2d00c85..703b820 splittedbranch -> master
上面的一串命令将parent项目的mysubtree目录被splitted到splittedbranch上(当你checkout这个splittedbranch时,你看到的就只有这个目录的文件了!),随后将该branch上的内容push到remote中,这就形成了独立的repo了。随后你要做的是在父项目中,将该子文件夹删除,通过git subtree来引用这个共享的repo
http://blog.nwcadence.com/git-subtrees/
注意:git filter-branch 也可以实现类似的git subtree split的功能,将一个repo的部分目录分割为一个新的repo.
具体可参考: https://help.github.com/articles/splitting-a-subfolder-out-into-a-new-repository/
另外一篇文章: http://log.pardus.de/2012/08/modular-git-with-git-subtree.html 可以参考更好的思路
git subtree有效管理公共第三方lib的更多相关文章
- git subtree:无缝管理通用子项目
移动互联网的爆发以及响应式页面的尴尬症,开发web和mobile项目成为了标配,当然实际情况下,会有更多的项目. 多项目开发对于前端来说是个很大的挑战✦ 重复,重复的前端架构,重复的前端依赖,重复的工 ...
- git subtree模块化代码管理
Git Subtree 的原理 首先,你有两个伟大的项目——我们叫他P1项目.P2项目,还有一个牛逼的要被多个项目共用的项目——我们叫他S项目.我们通过简要讲解使用Subtree来同步代码的过程来解释 ...
- git subtree 使用
这个是备忘录.原网页(https://medium.com/@porteneuve/mastering-git-subtrees-943d29a798ec , http://cncc.bingj.co ...
- Git subtree和Git submodule
git submodule允许其他的仓库指定以一个commit嵌入仓库的子目录. git subtree替代git submodule命令,合并子仓库到项目中的子目录.不用像submodule那样每次 ...
- git subtree pull 错误 Working tree has modifications
git subtree 是不错的东西,用于 git 管理子项目. 本文记录我遇到问题和翻译网上的答案. 当我开始 pull 的时候,使用下面的代码 git subtree pull --prefix= ...
- 使用GIT SUBTREE集成项目到子目录(转)
原文:http://aoxuis.me/post/2013-08-06-git-subtree 使用场景 例如,在项目Game中有一个子目录AI.Game和AI分别是一个独立的git项目,可以分开维护 ...
- iOS开发进阶 - 使用Carthage管理iOS第三方库
移动端访问不佳,请访问我的个人博客 最近在研究Swift,一不小心发现一个好的的管理iOS第三方库Carthage,就跟第一次使用CocoaPods时一样兴奋不已,在研究了大半天后终于能用了,使用起来 ...
- 使用scm-manager搭建git/svn 代码管理仓库
使用 scm-manager 搭建 git/svn 代码管理仓库 1.在官网上下载scm-manager 下载地址https://www.scm-manager.org/download/ 2. 配置 ...
- git的介绍、git的功能特性、git工作流程、git 过滤文件、git多分支管理、远程仓库、把路飞项目传到远程仓库(非空的)、ssh链接远程仓库,协同开发
Git(读音为/gɪt/)是一个开源的分布式版本控制系统,可以有效.高速地处理从很小到非常大的项目版本管理. [1] 也是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源码 ...
随机推荐
- Using Hooks
The following code examples demonstrate how to perform the following tasks associated with hooks: In ...
- 一个利用window.name实现的windowStorage
//key:value|key:value var windowStorage = { _inited: false, _data: {}, init: function(str) { var tmp ...
- ZendStudio导入一个已有的网站
解决方法:新建'PHP Project',选择'Create project at existiong location(from existing source)',路径指向你的网站根目录.
- eclipse 自动 注释
在使用Eclipse 编写Java代码时,自动生成的注释信息都是按照预先设置好的格式生成的. 修改作者.日期注释格式:打开Windows->Preferences->Java->Co ...
- ZOJ3560 Re:the Princess(高斯消元法)
题目要读很久才能理解它的意思和笑点(如果你也看过那个笑话的话),读懂之后就会发现是一个高斯消元法的题目,对于我来说难点不在高斯消元,而在于字符串处理.先来说说题意吧: 总共有n个人,n个人都会有一段话 ...
- 历代诗词咏宁夏注释3----蔡升元:<题大清渠>
题大清渠 蔡升元 为怜□□□□□,□□□□□□□. □□□□沙碛里,凿开峡口贺兰旁. 支分九堡通沟浍,鼎峙三渠并汉唐. 作吏尽如君任事,不难到处乐丰穰. 两渠中划大清渠,畚筑无劳民力纾.[1] 心画万 ...
- 优化DB2缓冲页的大小
零部件日结无法进行下去,建议配置C:\Program Files\SQLLIB目录下的db2cli.ini文件,加入此节:[DMSCNDB]CLIPkg=5 并重启DB2试试 另外,可以在命令行处理器 ...
- Codeforces Round #335 (Div. 2) C. Sorting Railway Cars 连续LIS
C. Sorting Railway Cars An infinitely long railway has a train consisting of n cars, numbered from ...
- 可任意自定义的 UITableViewCell
可任意自定义的 UITableViewCell UITableView的强大更多程度上来自于可以任意自定义UITableViewCell单元格.通常,UITableView中的Cell是动态的,在使用 ...
- C语言标准
1,K&R C 1978年, Dennis Ritchie和Brian Wilson Kernighan合作出版了<The C Programming Language>的第一版. ...