How do multiple repos share dir/code/module/repo, some solutions as below:
- git subtree
一般不可忍受:子仓库的记录,一旦被主仓库拉取,子仓历史commit记录全都进入主仓;未来在本地主仓更改了子仓代码,在主仓提交后,然后同步到子仓远端,这样的正常操作,主仓的commit其实融合了子仓的代码改动的,显得混乱。而submodule就很纯粹,子仓的更新commit永远在子仓, 主仓仅仅是指定选用子仓的某个commit拉取过来用而已,父子联系上仅仅一个commit号即可。 - git fetch && checkout方式 merge 子仓库代码 到 主仓库指定的目录
很强不可忍受点:与手动从子仓库拷贝代码到主仓库方式一样,这些diff,又会出现在主仓库 又需要重新在主仓库commit。。。 - soft link (电脑上建立目录软链)
较强不可忍受点:.gitignore是忽略了主仓库中的 子仓库的所有代码的,相当于远端代码库 缺了这一块,然而,连这块的关联信息 该如何解决? 一般不可忍受点:在VSC主仓库修改了子仓库代码,(可以忍受:需要去真正的子仓库去提交代码),就必然会多开一个子仓库窗口 进行git操作。 - git submodule
需要注意地方:在主仓库中修改子仓库,通过命令先提交子仓库代码,再提交主仓库代码。认为这是顺理成章的,因为子仓库代码改动,本该独立更新越来越觉得,这是软链的增强版
- 主仓库远端,缺失的子仓库这一块,但
.gitmodule
能表示与具体子仓库的关联关系 - 在VSC主仓库修改了子仓库代码,可以在主仓库,打包几个命令,做到在主仓库直接维护子仓库。
- 主仓库远端,缺失的子仓库这一块,但
- multiple workspace
暂未实践
├── README.md 当前文件
└── app 应用代码目录
├── base_shared 基础设施代码 **与其它项目可共享的**
│ ├── components
│ │ └── list
│ │ └── base.js
│ └── utils
│ └── theme
│ └── index.js
├── common 常用组件、工具代码 非共享的、MainRepoDemo才会用到的
│ ├── components
│ │ └── navigationBar
│ │ └── index.js
│ └── utils
│ └── time
│ └── index.js
└── modules 模块集合,存放MainRepoDemo用到的各业务模块
├── graphic_shared graphic模块 **共享自(来自于)其他项目**
└── home
└── index.js
- 添加 GraphicRepoDemo 仓库作为远程仓库,以便后续使用它的内容
git remote add graphicproject-remote git@github.com:zyestin/GraphicRepoDemo.git
- 使用 Git subtree 将 "GraphicRepoDemo" 的 "app/modules/graphic_shared" 目录合并到 "MainRepoDemo" 仓库的相同路径下。运行以下命令:
git subtree add --prefix=app/modules/graphic_shared graphicproject-remote master --squash
但结果却是 把GraphicRepoDemo
全部代码 合并到了 MainRepoDemo
的"app/modules/graphic_shared" 目录下。 确实做到了commit信息继续,而不产生新的commit信息
既然希望commit信息继续保留(范围是整个GraphicRepoDemo仓库) 而不会产生新的commit,又希望指定仓库中的一个子目录"app/modules/graphic_shared"(范围并不是整个仓库)来merge,看来本该就是做不到了,不管用不用subtree
于是,需要将graphic_shared
单独作为一个仓库,供MainRepoDemo
和GraphicRepoDemo
用subtree方式享用,即可~
-
将
GraphicRepoDemo
下"app/modules/graphic_shared"内的文件转移到 GraphicRepo -
删掉
MainRepoDemo
和GraphicRepoDemo
下"app/modules/graphic_shared"
拿MainRepoDemo试一试
- 移除
MainRepoDemo
之前的subtree
git remote remove graphicproject-remote
- 为
MainRepoDemo
添加子仓库
git remote add graphicrepo git@github.com:zyestin/GraphicRepo.git
git subtree add --prefix=app/modules/graphic_shared graphicrepo main --squash
这样,
- 在父仓库
MainRepoDemo
中更新了子仓库中的内容,同步到子仓库
//先提交父仓库
git add
git commit
//再提交到子仓库
git subtree push --prefix=app/modules/graphic_shared graphicrepo main
git push using: graphicrepo main
Enumerating objects: 55, done.
Counting objects: 100% (55/55), done.
Delta compression using up to 8 threads
Compressing objects: 100% (42/42), done.
Writing objects: 100% (50/50), 7.40 KiB | 2.47 MiB/s, done.
Total 50 (delta 10), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (10/10), completed with 1 local object.
To github.com:zyestin/GraphicRepo.git
0cb8da2..ff099bb ff099bbbc7ac3939ec0073f1bdc302fa4f5bfc26 -> main
注:应该是某种操作导致,正常使用不会这样(吓人情况 主仓一堆commit记录跑到子仓去了)。 正常情况下,在本地主仓更改了子仓,提交主仓后,若同步到子仓,仅仅只是从主仓中挑出属于子仓代码 进行合并提交到子仓远端。
- 子仓库 pull 可以看到,在父仓库对子仓库做的修改,已经同步过来了
可见,虽然在父仓库对子仓库做的修改后 可以通过subtree push
将更改同步到子仓库,但是 子仓库的commit信息,竟然被污染了!!!
执行如下命令
git fetch graphicproject-remote
git checkout graphicproject-remote/main -- app/modules/graphic_shared
类似于手动 从GraphicRepoDemo
把"app/modules/graphic_shared"拷贝,黏贴到MainRepoDemo
的该目录
在本地MainRepoDemo
的"app/modules/graphic_shared",通过软链指向GraphicRepoDemo
的"app/modules/graphic_shared"
注意:.gitignore
中需要忽略"app/modules/graphic_shared",防止提交了这个软链空壳文件上去
拿GraphicRepoDemo试一试 往里面关联 一个新的子仓库Graphic2Repo
pwd
/Users/yestin/Desktop/gitfiles/RepoShare/GraphicRepoDemo
git submodule add git@github.com:zyestin/Graphic2Repo.git app/modules/graphic_shared
实际的app/modules/graphic_shared
目录下的文件,是与 子仓库Graphic2Repo
代码 一致的
git submodule update --remote app/modules/graphic_shared
Submodule path 'app/modules/graphic_shared': checked out '68e524d1b15e3d678a094e83e6a02d3cb8116fc8'
git status
变化:仅app/modules/graphic_shared
的commit id
变化了
实际代码变化:父仓库app/modules/graphic_shared
内代码与子仓库一致了
发现,此时仅子仓库的git status
有变化。
- commit
cd app/modules/graphic_shared
git add .
git commit -m "test: 在父仓库更改子仓库代码,更新远端子仓库代码"
commit后,父仓库下git status
就有变化了,app/modules/graphic_shared
的commit id
变化了
- push 子仓库的改动同步到远端子仓库
- 通过命令
下图可见,子仓库的git log非常纯粹,commit 都是子仓库代码改动信息
cd app/modules/graphic_shared //... add commit ... 可直接在VSC操作 git push origin HEAD:graphic2-remote //可以指定 main 或别的 远程分支 Enumerating objects: 10, done. Counting objects: 100% (10/10), done. Delta compression using up to 8 threads Compressing objects: 100% (4/4), done. Writing objects: 100% (6/6), 629 bytes | 629.00 KiB/s, done. Total 6 (delta 2), reused 0 (delta 0), pack-reused 0 remote: Resolving deltas: 100% (2/2), completed with 1 local object. To github.com:zyestin/Graphic2Repo.git 16b612c..0833e03 HEAD -> graphic2-remote
- 通过VSC也可以push子仓库代码
- 通过命令
一般
git push
前还是先git pull
一次,以免他人push了,就会报如下错误
报这个错的话,就执行git config pull.rebase false
,然后再pull
git pull origin graphic2-remote
From github.com:zyestin/Graphic2Repo
* branch graphic2-remote -> FETCH_HEAD
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
- 对于首次,直接操作
submodule update
? 不,首次需要先操作git submodule update --init
他人首次拉取GraphicRepoDemo后,会发现app/modules/graphic_shared
目录下的代码是空的,看来需要额外的操作去同步这块代码
git submodule update --init --recursive 15:30:27
Submodule 'app/modules/graphic_shared' (git@github.com:zyestin/Graphic2Repo.git) registered for path 'app/modules/graphic_shared'
Cloning into '/Users/yestin/Desktop/gitfiles/RepoShare/GraphicRepoDemo2/app/modules/graphic_shared'...
Submodule path 'app/modules/graphic_shared': checked out '6ee3837c117a0f9b2696f3f0b3099ff21333b235'
操作完git submodule update --init --recursive
发现app/modules/graphic_shared
目录下的代码已经同步过来了
直接操作,会出现什么问题呢?会有如下提示
git submodule update --remote app/modules/graphic_shared
Submodule path 'app/modules/graphic_shared' not initialized
Maybe you want to use 'update --init'?
- 非首次,操作
git submodule update --remote app/modules/graphic_shared
- 当一个同事更新了 子仓库Graphic2Repo 其他同事如何感知呢?
使用sourcetree的同事,在主仓库是感知不到有未pull的commit的,(VSC本来就不支持提示有N个待pull的commit) 此时可以打开VSC的commit graph
可视化窗口,能看出是否有待pull的commit,如下图
- 当一个同事更新了 子仓库Graphic2Repo 其他同事如何感知呢?
git submodule update --remote app/modules/graphic_shared
Submodule path 'app/modules/graphic_shared': checked out '3ab3f32779995d68522878d563dfb63bfbd5f2ab'
本以为 .gitmodule文件中记录了
path = app/modules/graphic_shared
,以为直接执行git submodule update
,不用指定路径了, 但依然需要执行完整的git submodule update --remote app/modules/graphic_shared
- 没有冲突时
在主仓改子仓,commit但不push;
在子仓改,commit且push
- 有冲突时
VSC操作
Sync Changes
后,正常走熟悉的merge流程,标记出了冲突代码
commit: 父仓库直接提交父子仓库目录里的变动。若修改了子仓库的文件,则需要执行 subtree push
四个方案个人认为的排序是subtree = submodule > dll > npm
- GPT 对比 subtree与submodule