我正在寻找一种方法来设置git存储库,其中包含来自更大存储库的文件子集,并从该主存储库继承历史记录。我的主要动机是能够通过GitHub共享代码的子集。
我目前通过单个git存储库管理我的研究相关(主要是Matlab)代码。代码本身被松散地组织成少数文件夹,其代码依赖性经常跨越文件夹。我不想上传整个存储库的远程副本,因为它包含了许多其他人不想要的混合项目。
我的精神图片涉及每个项目的单独存储库,该存储库仅跟踪该项目的相关文件,但继承了主存储库中的所有提交。理想情况下,我希望能够将这些子存储库中的版本与主存储库中的版本分开,但这不是必需的。我查看了git子模块,子树和gitslave,但所有这些似乎都假设子项目是文件的隔离集合,而在我的情况下,许多子项目与其他子项目共享文件。我还尝试创建一个特定于项目的分支,git rm
- 不相关的文件,但是一旦我需要将更改从主分支合并到项目分支(由于更改导致的一系列冲突),我就会崩溃项目删除的文件)。
统计数据:
我目前只是通过将每个项目的相关文件定期复制到新文件夹来共享代码。但这意味着新副本没有附加提交历史记录。是否有更强大的方法来共享这些不同的代码子集,并使它与我所做的更改保持同步?
答案 0 :(得分:1)
据我所知,您的问题
git subtree
将文件的一部分历史记录提取到专用分支(然后可以将其推送到专用存储库)的一种方法是使用git submodules
:
git filter-branch
这将
# regex to match the files included in this subproject, used below
file_list_regex='^subproject1/|^shared_file1$|^lib/shared_lib2$'
git checkout -b subproject1 # create new branch from current HEAD
git filter-branch --prune-empty \
--index-filter "git ls-files --cached | grep -v -E '$file_list_regex' | xargs -r git rm --cached" \
HEAD
(subproject1
)创建一个新的分支HEAD
git checkout -b subproject1
)git filter-branch [...] HEAD
的部分的所有文件(xargs -r git rm --cached
)git ls-files --cached | grep -v -E '$file_list_regex'
)中删除。--prune-empty
/ --index-filter
)起作用。这是一次一次性操作,但是据我了解您的问题,您想用新的提交连续更新提取的子项目存储库/分支。
好消息是,您可以重复执行此命令,因为--cached
始终会为子项目分支产生相同的提交/历史记录-假设您不手动更改它们或重写主分支。
这样做的缺点是,每次{em} {em} {em} 完整的历史记录,每个子项目一次又一次。
假设您只想将git filter-branch
分支的最后5次提交添加到现有filter-branch
分支的尖端,则可以修改以下命令:
master
说明:
subproject1
为止的最近5次提交(# get the full commit ids for the commits we consider
# to be equivalent in master and subproject1 branch
common_base_commit="$(git rev-parse master~6)"
subproject_tip="$(git rev-parse subproject1)"
# checkout a detached HEAD so we don't change the master branch
git checkout --detach master
git filter-branch --prune-empty \
--index-filter "git ls-files --cached | grep -v -E '$file_list_regex' | xargs -r git rm --cached" \
--parent-filter "sed s/${common_base_commit}/${subproject_tip}/g" \
${common_base_commit}..HEAD
# force reset subproject1 branch to current HEAD
git branch -f subproject1
),我们认为这是对git filter-branch [...] ${common_base_commit}..HEAD
当前提示的等同提交。master~6
到subproject1
(master~6
)重写其父级,从而有效地将5个重写的提交重新置于subproject1
之上。 --parent-filter 'sed s/${common_base_commit}/${subproject_tip}/g'
即可在其顶部包括新提交。进一步的优化/自动化:
subproject1
)或实际上要从给定子项目中排除(subproject1
)的文件$file_list_regex
)或将列表签入存储库本身,以防每个子项目要包含的文件随时间变化git ls-files --cached | grep -v -E '$file_list_regex'
答案 1 :(得分:0)
首先让我总结一下您的问题:
从您的统计信息中,我可以看到您有14个子项目存储在一个主资源库中。这通常是一个非常糟糕的解决方案,因为请记住,每当有人克隆存储库时,它也会获得所有子项目的完整历史记录。例如,如果我想为您的一个子项目做贡献,那么我不想携带您拥有的所有8096文件。
如果项目彼此无关,则将其拆分为子存储库。使用GitHub,您可以创建organizations。不要犹豫创建自己的组织,并将所有子项目放入其中。主要优点是每个子项目将具有:
如果您有相关项目,则每个项目都需要从特定提交中获取。我建议您使用git submodules。例如,如果您查看ext/
文件夹中的TortoiseGit project,则会注意到指向其他存储库的链接。
另一种解决方案是使用git subtree,这似乎并不是解决您问题的最佳方法。
如果您的主存储库属于以下任何类别,则应查看使用Git的方式:
.exe
,.tmp
,二进制文件,生成的文件,.pdf
...)您的存储库在GitHub上公开吗?
答案 2 :(得分:0)
您正在寻找git submodules:
在一个项目上工作时,经常需要在其中使用另一个项目。也许这是第三方开发的图书馆,或者您是在单独开发并在多个父项目中使用的图书馆。在这些情况下会出现一个常见问题:您希望能够将这两个项目视为独立的项目,但仍然能够在另一个项目中使用它们。
子模块上的TL; DR是它们是包含在其他存储库中的存储库。
父级回购协议唯一了解子级的是子级告知的最后一次提交的SHA,因此每个回购协议都是相互独立管理的,但是它们相互引用,因此您可以编写它们在一起。
这是该主题上写得好的blog post from GitHub。