git subtree相关问题

使用git subtree有一段时间了,主要用来解决多个项目共同使用相同代码的同步问题,特意简单整理了一下相关知识点以及使用过程中遇到的问题。

git subtree是什么?

git subtree 可以实现一个仓库作为其他仓库的子仓库。
subtree的核心思想与能做的就只有同步项目文件。

  • 假如有P1 、P2两个项目,两个项目存在共用的代码,将共用的代码独立为新的git仓库——share项目。
  • 当你对P1/P2项目操作git clone或者git pull的时候,你拉取到的是整个P1/P2项目,包括share在内,share对于父级的主项目来说相当于是个普通目录;
  • 当你在P1/P2项目修改了share里的内容后执行git push,修改的share文件将像其他普通文件那样push到P1/P2项目上。

subtree本质就是把子项目目录作为一个普通的文件目录,对于父级的主项目来说是完全透明的,真的就是个普通目录,原来是怎么操作现在依旧是那么操作,就像操作主项目中其他文件一样的 add commit。

什么时候需要 subtree ?

1、当多个项目共用同一坨代码,而这坨代码跟着项目在快速更新的时候
2、把一部分代码迁移出去独立为一个新的 git 仓库,但又希望能够保留这部分代码的历史提交记录。

如何使用git subtree?

1.确保各个项目已经添加这个 remote(可选,方便后续用别名代替)
// git remote add  <S项目别名>  <S项目远程库仓库地址>
git remote add share http://xx.git
2.关联subtree(只需要执行关联操作git subtree add即可,无需对share项目执行git clone)
// git subtree add --prefix=<S项目的相对路径> <S项目远程库仓库地址 | S项目远程库别名> <分支> --squash
git subtree add --prefix=src/share share master --squash // 假设将share放在src目录下的
  • --prefix之后的=等号也可以用空格
  • --squash意思是把subtree的改动合并成一次commit,这样就不用拉取子项目完整的历史记录。如果不加 --squash 参数,主项目会合并子项目本身所有的 commit 历史记录,加上 --squash 参数是把子项目的记录合成一次 commit 提交到主项目,这样主项目只是合并一次 commit 记录。
3. 提交更改到子项目
// git subtree push --prefix=<S项目的相对路径> <S项目远程库仓库地址 | S项目远程库别名> <S项目分支>
git subtree push --prefix=src/share share master

高阶:每次push命令都会遍历全部的commit,当你的项目越来越大,commit的数上来的时候,等待时间就会很长。--rejoin 避免了遍历全部commit的问题.

//git subtree split --rejoin --prefix=<S项目的相对路径> --branch <临时branch>
git subtree split --rejoin --prefix=src/share --branch srcTemp
//git push <S项目远程库仓库地址 | S项目远程库别名> srcTemp:master
git push share srcTemp:master
4.更新子目录:
// git subtree pull --prefix=<S项目的相对路径> <S项目远程库仓库地址 | S项目远程库别名> <分支> --squash
git subtree pull --prefix=src/share share master --squash

参考文章:
用 Git Subtree 在多个 Git 项目间双向同步子项目
Git Subtree的使用

git subtree 要不要使用 –squash 参数

使用 --squash 参数
  • 就是把 subtree 子项目的更新记录进行合并,再合并到主项目中:subtree add 或者 pull 操作的结果对应两个 commit, 一个是 squash 了子项目的历史记录, 一个是 Merge 到主项目中。

优点:主项目的历史记录看起来还是比较整齐的。
缺点:在子项目需要 subtree pull 的时候,经常需要处理冲突,甚至每次 subtree pull 的时候都需要重复处理同样的冲突。
原因:subtree add/pull 操作中,需要用到 merge,而 merge 顺利进行的前提, 是要有相同的 parent commit。原子项目历史记录被合并后就消失了,相当于一个“新”的提交。 下次再进行 add/pull 时,新添加的内容找不到“上一次的修改”, 于是在更新 subtree 内文件的时候,就会提示冲突,需要手工解决。

不使用 --squash 参数

优点:子项目更新的时候,subtree pull 很顺利, 能够自动处理已解决过的冲突。
原因: 原子项目的历史复制到了父项目中, 下次再进行 add/pull 时,新增的 commit 能够找到“上一次的修改”, 那么他会像在子项目中逐个 am patch 那样更新 subtree 下的内容, 不会提示冲突。
缺点:子项目的更新记录“污染”了主项目的。

总结

是否使用 squash 都是可以的, 但需要在开始阶段作出选择,并 一直坚持下去 。 如果一会儿用一会儿不用,得到的不是两者的优点,而是两者的缺点之和。

既希望能够比较顺利的更新子项目, 又不希望子项目的历史记录直接合并在主项目中,请参考文章:
Git subtree 要不要使用 –squash 参数

git subtree使用过程中的问题&解决方案

问题1:执行提交操作不成功

$ git subtree push --prefix=src/share share master
 ! [rejected]        fc1de0e69c29fa1269feef734813f7889141859f -> master (non-fast-forward)
error: failed to push some refs to 'http://xxxx.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

解决方案:

// git push <your subtree's origin> `git subtree split --prefix=Path/to/subtree master`:master --force
git push share `git subtree split --prefix=src/share master`:master --force

问题2:执行了以上命令,又出现新的问题

$ git push share `git subtree split --prefix=src/share master`:master --force
To http://xxx.git
 ! [remote rejected] fc1de0e69c29fa1269feef734813f7889141859f -> master (Git:You are not allowed to force push code to a protected branch on this project.)
error: failed to push some refs to 'http://xxx.git'

解决方案:
进入git页面,按照以下路径,点击un-protext按钮解除保护,再重新执行上面的操作
project settings->protected branches-> click un-protect.g

问题3:执行更新操作不成功

$ git subtree pull --prefix=src/share share master
Working tree has modifications.  Cannot add.

解决方案:
项目有代码没提交,需要提交后才能执行pull

参考文章:
Git subtree - subtree up-to-date but can't push
Heroku deployment without the app being at the repo root (in a subfolder)
You are not allowed to push code to this project....! [remote rejected] master -> master (pre-receive hook declined)

原文:
git subtree相关问题

推荐文章:
前端开发之走进Vue.js(入门知识点)
快速掌握vue组件间的通讯
快速理解Vuex
如何在Vue+Webpack下配置Stylelint
Highchart属性笔记

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335