git subtree有效管理公共第三方lib

摘要:
如果您的项目中有许多第三方库,您希望使用它们,并且还希望修改这些库并将它们贡献给原始项目,或者您的项目希望通过几个repo进行模块化和单独维护,那么gitsubtree是一个选项。由gitsubtree管理的子项目在父项目中作为完整的代码副本存在,并且不包含历史信息。考虑到gitsubree和gitsubtree模块的优缺点,一种可行的管理策略是使用gitsubtree

  如果你的项目中有很多第三方的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
# make
prefix=/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: 3, done.                                                                                                                                         
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0                                                                                                               
Unpacking objects: 100% (3/3), 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 12                                                                                                                                                                   
drwxrwxr-x 2 cabox cabox 4096 May 31 02:14 .                                                                                                                               
drwxrwxr-x 4 cabox cabox 4096 May 31 02:14 ..                                                                                                                              
-rw-rw-r-- 1 cabox cabox   14 May 31 02:14 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 2 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: 5, done.                                                                                                                                                 
Delta compression using up to 12 threads.                                                                                                                                  
Compressing objects: 100% (3/3), done.                                                                                                                                     
Writing objects: 100% (5/5), 528 bytes | 0 bytes/s, done.                                                                                                                  
Total 5 (delta 0), reused 0 (delta 0)                                                                                                                                      
To https://github.com/cnweibo/subtree-p.git                                                                                                                                
   67da25d..c1e6018  master -> master       

这时,我们查看在github上的subtree-p repo,你就可以看到这个父项目已经引入了mysubtree(代表了subtree-sub repo!)

git subtree有效管理公共第三方lib第1张

现在我们在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                                                                                                                         
 1 file changed, 1 insertion(+)                                                                                                                                            
 create mode 100644 mysubtree/subfile1                                                                                                                                     
(master)$ git s                                                                                                                                                            
On branch master                                                                                                                                                           
Your branch is ahead of 'origin/master' by 1 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: 4, done.                                                                                                                                                 
Delta compression using up to 12 threads.                                                                                                                                  
Compressing objects: 100% (3/3), done.                                                                                                                                     
Writing objects: 100% (4/4), 398 bytes | 0 bytes/s, done.                                                                                                                  
Total 4 (delta 0), reused 0 (delta 0)                                                                                                                                      
To https://github.com/cnweibo/subtree-p.git                                                                                                                                
   c1e6018..ed30a68  master -> master                                                                                                                                      
(master)$                      

这时我们再查看github上的subtree-p我们就能看到我们对子项目的新的改动了:

git subtree有效管理公共第三方lib第2张

我们来继续模拟代码开发过程:修改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                                                                                                                       
 2 files changed, 2 insertions(+), 2 deletions(-)                                                                                                                          
 create mode 100644 mysubtree/subfileNew2                                                                                                                                  
(master)$ git push                                                                                                                                                         
Username for 'https://github.com': kidsit                                                                                                                                  
Password for 'https://kidsit@github.com':                                                                                                                                  
Counting objects: 5, done.                                                                                                                                                 
Delta compression using up to 12 threads.                                                                                                                                  
Compressing objects: 100% (3/3), done.                                                                                                                                     
Writing objects: 100% (5/5), 461 bytes | 0 bytes/s, done.                                                                                                                  
Total 5 (delta 0), reused 0 (delta 0)                                                                                                                                      
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: 5, done.                                                                                                                                                 
Delta compression using up to 12 threads.                                                                                                                                  
Compressing objects: 100% (3/3), done.                                                                                                                                     
Writing objects: 100% (5/5), 461 bytes | 0 bytes/s, done.                                                                                                                  
Total 5 (delta 0), reused 0 (delta 0)                                                                                                                                      
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: 6, done.                                                                                                                                                 
Delta compression using up to 12 threads.                                                                                                                                  
Compressing objects: 100% (4/4), done.                                                                                                                                     
Writing objects: 100% (6/6), 563 bytes | 0 bytes/s, done.                                                                                                                  
Total 6 (delta 1), reused 0 (delta 0)                                                                                                                                      
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: 3, done.                                                                                                                                         
remote: Compressing objects: 100% (3/3), done.                                                                                                                             
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0                                                                                                               
Unpacking objects: 100% (3/3), 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 | 1 +                                                                                                                       
 1 file changed, 1 insertion(+)                                                                                                                                            
 create mode 100644 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 2                                                                                                                                                              
* 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: 8, done.                                                                                                                                                 
Delta compression using up to 12 threads.                                                                                                                                  
Compressing objects: 100% (8/8), done.                                                                                                                                     
Writing objects: 100% (8/8), 1.06 KiB | 0 bytes/s, done.                                                                                                                   
Total 8 (delta 1), reused 0 (delta 0)                                                                                                                                      
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: 15, done.                                                                                                                                                
Delta compression using up to 12 threads.                                                                                                                                  
Compressing objects: 100% (11/11), done.                                                                                                                                   
Writing objects: 100% (15/15), 1.43 KiB | 0 bytes/s, done.                                                                                                                 
Total 15 (delta 2), reused 0 (delta 0)                                                                                                                                     
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 subtree有效管理公共第三方lib第3张git subtree有效管理公共第三方lib第4张

注意: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》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇html页面输出pdf格式文件(一步步很详细)url加密并计算时间下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Eclipse和Git结合使用

这学期需要用eclipse开发,然后用git管理。我看见有很多人都是在本地的一个eclipse工作空间写程序,然后复制到特定的git仓库提交。(因为害怕会提交上去一些eclipse的东西比如.metadata文件。 我开始也是这样,但是后来和同学交流之后发现可以把eclipse和git结合。 就直接把git项目clone在工作空间里面。 里面.metad...

程序破解之 API HOOK技术 z

API HOOK,就是截获API调用的技术,在程序对一个API调用之前先执行你的函数,然后根据你的需要可以执行缺省的API调用或者进行其他处理,假设如果想截获一个进程对网络的访问,一般是几个socket API : recv,recvfrom, send, sendto等等,当然你可以用网络抓包工具,这里只介绍通过API HOOK的方式来实现, 主要原理是...

配置CentOS6.5的yum源

      系统yum源(源,英文repository,就是资源库的意思;yum,全称Yellow dog Updater, Modified,是centos的软件包管理器。基于RPM包管理,能够从指定的服务器自动下载RPM包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软件包。)的位置在/etc/yum.repos.d/,系统默认的是CentO...

GitHub源代码管理基本操作 Mossad

最近,我进行了结对编程,并阅读了一些相关的资料,在此基础上我认为结对编程的价值,或者说它能带来的好处,是显而易见的,显著提高代码质,促进知识分享及学习,帮助团队信任及合作,形成压力和专注.偶尔有几次,我一天做了5到6个小时的结对,之后的确感觉非常疲劳.在结对编程过程中,我发现清晰地表达自己是件比较困难的事情,但我发现耐性地倾听别人的话更难,在结对的时候,倾...

如何使用vb通过outlook收发邮件

 制作邮件发送、接收程序  原文地址:http://flydoos.blog.163.com/blog/static/11975604020095220422284/ 你还认识我吗?记得两年前我哥哥小飞侠教我学习VB编程的时候你还是一名旁听生呢。呵呵,我就是小叮当,自从上次和哥哥学习了VB之后就痴迷上了编写程序,凭借着我过人的编程技能和敏捷的思维能力,...

Windows上使用Git托管代码到Coding

作者:荒原之梦 Git简介: Git是一款分布式版本控制系统,可用于项目的版本管理。Git可以管理本地代码仓库与远程代码仓库间的连接以及进行版本控制,使得我们可以在本地离线进行修改等操作,之后再将代码提交到远程代码仓库,方便团队协作。 Git官网: https://git-scm.com/ Git百度百科: https://baike.baidu.co...