美文网首页Git使用GitGit
git subtree相关问题

git subtree相关问题

作者: Smileswlin | 来源:发表于2018-08-07 19:50 被阅读2次

    使用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属性笔记

    相关文章

      网友评论

      • ff702acbc63d:和git submodule 有啥区别吗?
        Smileswlin:@装象 git submodule也是一样用来作为同步代码的指令,但git官方后来推荐git subtree,我没有具体用过git submodule,参考文章里有说两者的区别以及优缺点,你可以看看

      本文标题:git subtree相关问题

      本文链接:https://www.haomeiwen.com/subject/jppfvftx.html