24

所以,我有一个更大的(封闭源代码)项目,并且在这个项目的上下文中创建了一个库,我认为它在其他地方也可能有用。

我现在想在自己的项目中拆分该库,该项目可以作为 github 或类似的开源项目。当然,图书馆(以及它的历史)不应该包含我们项目的任何痕迹。

git-subtree 在这里似乎是一个解决方案,但它并不完全适合。

我的目录布局是这样的(因为它是一个 Java 项目):

  • 击剑游戏 (git workdir)
    • 源代码
        • 击剑游戏
          • 交通 (我的图书馆)
            • 协议 (库的一部分)
            • 围栏(与图书馆接口的主要项目的一部分)
            • 客户端(与库接口的主要项目的一部分)
            • 服务器(与库接口的主项目的一部分)
          • 客户(主要项目的一部分)
          • 服务器(主项目的一部分)
          • ... (主要项目的一部分)
    • 其他文件和目录(构建系统、网站等 - 主项目的一部分)

拆分后,我希望库的目录布局如下所示(包括直接在粗体目录中的任何文件):

  • 我的图书馆(名称待定)
    • 源代码
        • 击剑游戏
          • 交通 (我的图书馆)
            • 协议 (库的一部分)

历史记录还应该只包含与存储库的这一部分相关的主项目历史记录的一部分。

第一眼看到我git-subtree split --prefix=src/de/fencing_ame/transport,但这会

  1. 给我一棵植根于的树transport(不会编译)和
  2. 包括transport/client,transport/servertransport/fencing目录。

第一点可以通过git subtree add --prefix=src/de/fencing_ame/transport <commit>在接收端使用来缓解,但我认为 git-subtree 对导出这些子目录也没有多大作用。(这个想法实际上是能够在这里分享完整的树)。

我必须在这里使用git filter-branch吗?

拆分后,我希望能够使用 git-subtree 或 git-submodule 将主项目中的库导入到单独的子目录中,而不是现在的位置。我想象这样的布局

  • 击剑游戏 (git workdir)
    • 源代码
        • 击剑游戏
          • 运输 (空)
            • 围栏(与图书馆接口的主要项目的一部分)
            • 客户端(与库接口的主要项目的一部分)
            • 服务器(与库接口的主项目的一部分)
          • 客户(主要项目的一部分)
          • 服务器(主项目的一部分)
          • ... (主要项目的一部分)
    • 我的图书馆
      • 源代码
          • 击剑游戏
            • 交通 (我的图书馆)
              • 协议 (库的一部分)
    • 其他文件和目录(构建系统、网站等 - 主项目的一部分)
这样做最无痛的方法是什么?除了 git-subtree 和 git-filter-branch 之外,还有其他工具可以实现这个目标吗?

4

5 回答 5

3

拆分与父项目中的文件混合的子树

这似乎是一个常见的要求,但是当文件夹像这样混合在一起时,我认为没有一个简单的答案。

我建议拆分与其他文件夹混合的库的一般方法是:

  1. 使用库的新根创建一个分支:

    git subtree split -P src/de/fencing_game -b temp-br
    git checkout temp-br
    
    # -or-, if you really want to keep the full path:
    
    git checkout -b temp-br
    cd src/de/fencing_game
    
  2. 然后使用某些东西来重写历史记录以删除不属于库的部分。我不是这方面的专家,但我能够进行实验并发现这样的工作:

    git filter-branch --tag-name-filter cat --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch client server otherstuff' HEAD
    
    # also clear out stuff from the sub dir
    cd transport 
    git filter-branch --tag-name-filter cat --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch fencing client server' HEAD
    

    注意:您可能需要删除 filter-branch 在连续命令之间所做的备份。

    git update-ref -d refs/original/refs/heads/temp-br
    
  3. 最后,只需为库创建一个新的 repo 并提取剩下的所有内容:

    cd <new-lib-repo>
    git init
    git pull <original-repo> temp-br
    

我建议您的最终库路径更像是/transport/protocol而不是完整的父项目路径,因为这似乎与项目相关。

于 2014-03-07T19:35:50.377 回答
3

我认为你有一些真正的探索要做。如果您只想拆分“协议”,可以使用“git subtree split ...”或“git filter-branch ...”来实现

git filter-branch --subdirectory-filter fencing-game/src/de/fencing_game/transport/protocol -- --all

但是,如果您在传输和传输/协议中有文件,它就会开始变得毛茸茸。

我为我正在进行的项目编写了一些自定义工具来执行此操作。它们没有在任何地方发布,但您可以使用reposurgeon做类似的事情。

于 2011-09-20T19:25:52.190 回答
2

这里的问题是没有很好的区分什么是和不是你的图书馆的一部分。我强烈建议重构解决方案,然后您可以将库作为子模块包含在内。

如果其他开发人员在同一个 repo 中重复使用这个库,只需在单独的分支上跟踪这些更改,不要打扰额外的 repo。

于 2011-06-19T17:25:40.103 回答
1

项目的历史是只为了你的利益,还是为了 github 上的人们的利益?

如果历史只是为了您的利益,那么有一种使用移植物的简单方法。基本上,只需为 github 创建一个全新的存储库,删除所有专有代码。现在你有了一个只有公共代码的开源仓库,你可以将它推送到 github。在开源存储库的本地副本中,您可以将专有存储库中的历史移植到开源存储库中。

这样做意味着您(或任何有权访问专有存储库的人)可以看到完整的历史记录,但公众只能从您开源的那一刻看到代码。

.git/info/grafts 有什么用?

于 2011-06-19T17:23:20.270 回答
1

我做了类似的事情,但是将几个目录拆分为加密分区(/secure/tmp/newrepo)上的一个完全独立的存储库,因此笔记本电脑窃贼无法使用它们。我编写了 shell 脚本,然后执行了: git filter-branch --tree-filter '~/bin/tryit /secure/tmp/newrepo personal private' -- 95768021ff00216855868d12556137115b2789610..HEAD (SHA 在任一目录存在之前避免提交)


#!/bin/sh
# to be used with  e.g:
# git filter-branch --tree-filter '~/bin/tryit /secure/tmp/newrepo personal private' 
# Don't do it on any repository you can't repeatedly do: 
#   rm -rf foo ; git clone /wherever/is/foo 
# when it breaks
SRC=`pwd`
DEST=$1
shift
MSG=/dev/shm/msg.txt
TAR=/dev/shm/tmp.tar
LIST=/dev/shm/list.txt
LOG=/dev/shm/log
DONE=''

echo $GIT_AUTHOR_DATE >> $LOG
git show --raw $GIT_COMMIT > $MSG 

for A in $* 
do 

if [ -d $A ] 
then 
DONE=${DONE}x
tar -cf $TAR $A 
tar -tf $TAR > ${LIST}
cat ${LIST} >> ${LOG}
rm -rf ${A}
cd ${DEST}
tar -xf $TAR
else
echo $A non-existant >> ${LOG}
fi
cd $SRC
done

if [ -z "${DONE}" ]
then
echo Empty >>$LOG
else
cd ${DEST}
unset GIT_INDEX_FILE
unset GIT_DIR
unset GIT_COMMIT
unset GIT_WORK_TREE
touch foo
git add .
git commit -a -F ${MSG}  >> ${LOG}
fi
exit 0

出于您的目的,您可能希望对 tar 有不同的规范(例如 --exclude= ),然后使用 cat ${LIST} | xargs rm 仅删除 tar 中的内容,但我希望做到这一点并不太难。

未设置的东西和退出 0 很重要,因为 filter-branch 将它们设置为您的源代码库(不是您想要的!)并且如果 sh 从脚本中的最后一个命令传递非零退出代码,它将死亡。

于 2012-01-04T14:41:33.190 回答