如何将单片项目转换为使用git子树

时间:2015-04-16 01:48:10

标签: git git-subtree

我有一个使用单个存储库的现有项目。目录结构如下所示:

* MyProject
  * client
  * server
  * tester
  * documentation
  * deployment
  * graphics

我想修改它,以便clientservertester是单独的存储库; MyProject仍然存在,其中包含其他子目录,并通过client托管git subtree等。

所以最终的结果是我有相同的目录结构,但我可以单独对client等进行版本控制,而不会打扰其余的回购。

我应该用什么命令来实现这个目标?我有权登录远程repo的服务器并直接在repo上发出git命令。


额外额外奖励:目前我已在client的历史记录中同时获得了MyProject的所有提交。如果可能的话,我想保留这个新的子树项目的历史。

2 个答案:

答案 0 :(得分:0)

我刚刚阅读了一个关于子树的非常有趣的页面:http://blogs.atlassian.com/2013/05/alternatives-to-git-submodule-git-subtree/

因此,如果没有远程跟踪,您可以执行以下操作:

1)他说要先创建子树,然后提供这个片段。要保留此目录中的历史记录,您只需避免使用“--squash”,但我认为此历史记录仍保存在主仓库中。

git subtree add --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git master

2)然后只需获取远程仓库

我怀疑你会想要遵循他的指示,包括远程跟踪,这是完全不同的。

答案 1 :(得分:0)

简介

这个答案基于this blog post,我直到今天才发现。

所需的步骤是:

  1. 如果clientservertester有单独的分支,则将它们展平(rebase或merge),以便单个提交具有所有
  2. 的最新版本
  3. 将每个目录拆分为自己的存储库(不带路径名!)
  4. 删除已从基础项目拆分的文件
  5. (可选)从基础项目中删除历史记录
  6. (可选)将新存储库重新添加为子树,子模块或嵌套存储库。
  7. 拆分目录

    使用git subtree可以轻松完成此操作。注意:git-subtree可能require installation

    将目录复制到其自己的存储库,其中目录的名称将从新存储库中的文件路径中删除(即tester/foo/bar.c在新存储库foo/bar.c中变为tester }),使用以下代码。这是tester的代码;我一次做了多个拆分我使用了一个shell for,当然也可以复制粘贴。

    另请参阅this thread,尽管在该主题中,OP希望将tester/foo/bar.c移至ABC/foo/bar.c

    在git主机上,你保留了你的存储库 - 我这样做是为了有兄弟姐妹Base,客户端,服务器,测试人员,但这并不重要:

    cd /path/to/base
    mkdir tester.git
    cd tester.git
    git init --bare
    

    在开发系统上(使用git remote -v查看您现有的遥控器;我使用ssh:

    git remote add sub_tester ssh://git_host/path/to/base/tester.git
    git checkout master;    # assume master for this demonstration
    git subtree split --prefix=tester -b split_tester
    git push sub_tester split_tester:master
    git branch -D split_tester
    

    subtree split命令在同一个repo中创建一个新根,将该目录中master个文件的所有历史提交复制到新根上的一个分支上,最后将其合并到master

    删除已拆分的文件

    现在你可以清除糠:

    git rm -r tester
    git add -A
    git commit -am "Removing tester which has been split to its own repo"
    

    删除历史记录

    新的回购在其中有历史,因此没有必要在基础回购中保留该历史记录。事实上,如果您稍后重新添加新的repos作为子树,那么您已经复制了所有历史记录。我通过以下步骤删除了历史记录:

    git checkout last_commit_to_keep
    git checkout --orphan history
    git commit -m "Squashed old history"
    git replace last_commit_to_keep history
    git branch -D history
    

    重新添加为子树

    现在您可以将单独的repos添加为子树:

    git subtree add --prefix-tester sub_tester master
    

    附录(并非真正相关):这样做之后我决定对我的工作流程来说,子树不是一个好主意。最大的问题是,如果在子树中的分支上进行更改,则必须每次将该分支合并到repo的主要部分。这会很快导致在gitk中查看时看起来像意大利面条的历史记录。

    或者,如果您在master上开发然后向后移植到子树,则没有任何检查可以阻止您与子树不同步,并且您可能必须保持合并以确保您保持在同步。

    我最终如上所述分裂,但随后使用子模块,结果更适合我的工作流程。通过压缩子模块更新提交可以保持整洁。

    当然,使用嵌套存储库是另一种选择,但是在不同的存储库之间根本没有相对版本控制。并且可以使用git clean意外删除它们。可能最适合我的是那些在嵌套的repos之间维护公共标记的强大脚本之一。